From c70f7ad9cbf460c5d58c799a49eebd00a63d0f10 Mon Sep 17 00:00:00 2001 From: Peeyush Aggarwal Date: Thu, 19 Jun 2014 15:54:03 -0700 Subject: [PATCH 001/207] Made reactor pool size configurable per memcachedclient object to set different pool size per client object --- pom.xml | 4 ++-- .../google/code/yanf4j/config/Configuration.java | 15 +++++++++++++++ .../xmemcached/XMemcachedClientBuilder.java | 16 +++++++++------- .../xmemcached/impl/MemcachedConnector.java | 5 +---- 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/pom.xml b/pom.xml index d61f08c5c..f7412c9c7 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ 4.0.0 com.googlecode.xmemcached xmemcached - 2.0.0 + 2.0.0-TANGO xmemcached Extreme performance modern memcached client for java http://code.google.com/p/xmemcached/ @@ -164,4 +164,4 @@ - \ No newline at end of file + diff --git a/src/main/java/com/google/code/yanf4j/config/Configuration.java b/src/main/java/com/google/code/yanf4j/config/Configuration.java index ecc2d07ec..e0c69b152 100644 --- a/src/main/java/com/google/code/yanf4j/config/Configuration.java +++ b/src/main/java/com/google/code/yanf4j/config/Configuration.java @@ -11,6 +11,10 @@ */ package com.google.code.yanf4j.config; +import net.rubyeye.xmemcached.impl.ReconnectRequest; + +import java.util.concurrent.DelayQueue; + /** * Networking configuration * @@ -19,6 +23,8 @@ */ public class Configuration { + public static final String XMEMCACHED_SELECTOR_POOL_SIZE = "xmemcached.selector.pool.size"; + /** * Read buffer size per connection */ @@ -54,6 +60,8 @@ public class Configuration { */ private int readThreadCount = 1; + private int selectorPoolSize = System.getProperty(XMEMCACHED_SELECTOR_POOL_SIZE) == null ? 2 * Runtime.getRuntime().availableProcessors() : Integer.parseInt(System.getProperty(XMEMCACHED_SELECTOR_POOL_SIZE)); + /** * Increasing buffer size per time */ @@ -176,4 +184,11 @@ public long getCheckSessionTimeoutInterval() { return this.checkSessionTimeoutInterval; } + public void setSelectorPoolSize(int selectorPoolSize) { + this.selectorPoolSize = selectorPoolSize; + } + + public int getSelectorPoolSize() { + return selectorPoolSize; + } } diff --git a/src/main/java/net/rubyeye/xmemcached/XMemcachedClientBuilder.java b/src/main/java/net/rubyeye/xmemcached/XMemcachedClientBuilder.java index a6670388e..5237a09bd 100644 --- a/src/main/java/net/rubyeye/xmemcached/XMemcachedClientBuilder.java +++ b/src/main/java/net/rubyeye/xmemcached/XMemcachedClientBuilder.java @@ -8,9 +8,6 @@ import java.util.List; import java.util.Map; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - import net.rubyeye.xmemcached.auth.AuthInfo; import net.rubyeye.xmemcached.buffer.BufferAllocator; import net.rubyeye.xmemcached.buffer.SimpleBufferAllocator; @@ -20,14 +17,15 @@ import net.rubyeye.xmemcached.impl.RandomMemcachedSessionLocaltor; import net.rubyeye.xmemcached.transcoders.SerializingTranscoder; import net.rubyeye.xmemcached.transcoders.Transcoder; -import net.rubyeye.xmemcached.utils.Protocol; import net.rubyeye.xmemcached.utils.AddrUtil; +import net.rubyeye.xmemcached.utils.Protocol; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.code.yanf4j.config.Configuration; import com.google.code.yanf4j.core.SocketOption; import com.google.code.yanf4j.core.impl.StandardSocketOption; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Builder pattern.Configure XmemcachedClient's options,then build it @@ -198,7 +196,7 @@ public static final Configuration getDefaultConfiguration() { configuration .setSessionIdleTimeout(MemcachedClient.DEFAULT_SESSION_IDLE_TIMEOUT); configuration.setWriteThreadCount(0); - return configuration; + return configuration; } public boolean isFailureMode() { @@ -437,4 +435,8 @@ public void setName(String name) { } + public void setSelectorPoolSize(int selectorPoolSize) { + getConfiguration().setSelectorPoolSize(selectorPoolSize); + } + } diff --git a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java index 04cf341be..ec3e73400 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java @@ -66,9 +66,6 @@ */ public class MemcachedConnector extends SocketChannelController implements Connector { - - public static final String XMEMCACHED_SELECTOR_POOL_SIZE = "xmemcached.selector.pool.size"; - public static final int DEFAULT_SELECTOR_POOL_SIZE = System.getProperty(XMEMCACHED_SELECTOR_POOL_SIZE) == null ? 2 * Runtime.getRuntime().availableProcessors() : Integer.parseInt(System.getProperty(XMEMCACHED_SELECTOR_POOL_SIZE)); private final DelayQueue waitingQueue = new DelayQueue(); private BufferAllocator bufferAllocator; @@ -604,7 +601,7 @@ public MemcachedConnector(Configuration configuration, this.soLingerOn = true; this.commandFactory = commandFactory; this.flowControl = new FlowControl(maxQueuedNoReplyOperations); - this.setSelectorPoolSize(DEFAULT_SELECTOR_POOL_SIZE); + this.setSelectorPoolSize(configuration.getSelectorPoolSize()); // setDispatchMessageThreadPoolSize(Runtime.getRuntime(). // availableProcessors()); } From 4f8797cb8072d9f0dbb8d9b7b38c95a6d4b5a663 Mon Sep 17 00:00:00 2001 From: tomjiang1987 Date: Tue, 23 Sep 2014 13:32:23 +0800 Subject: [PATCH 002/207] set heatbeat thread daemon --- .../java/net/rubyeye/xmemcached/impl/MemcachedConnector.java | 1 + .../java/net/rubyeye/xmemcached/impl/MemcachedHandler.java | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java index ec3e73400..e1331a5ae 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java @@ -556,6 +556,7 @@ public void onException(Controller controller, Throwable t) { } public void onReady(Controller controller) { + MemcachedConnector.this.sessionMonitor.setDaemon(true); MemcachedConnector.this.sessionMonitor.start(); } diff --git a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java index 61803ff6a..2bf2c426d 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java @@ -303,9 +303,7 @@ public void start() { new ThreadFactory() { public Thread newThread(Runnable r) { Thread t = new Thread(r, name + "-" + threadCounter.getAndIncrement()); - if (t.isDaemon()) { - t.setDaemon(false); - } + t.setDaemon(true); if (t.getPriority() != Thread.NORM_PRIORITY) { t.setPriority(Thread.NORM_PRIORITY); } From 1109ad44e8b4b3ef2ed3ff3efa4339b76ab4374f Mon Sep 17 00:00:00 2001 From: Jakub Narloch Date: Tue, 19 May 2015 16:42:44 +0200 Subject: [PATCH 003/207] Corrected the log placeholder. --- src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java index 61803ff6a..18dd910dc 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java @@ -185,7 +185,7 @@ public void onSessionIdle(Session session) { private void checkHeartBeat(Session session) { if (this.enableHeartBeat) { log.debug( - "Check session (%s) is alive,send heartbeat", + "Check session ({}) is alive,send heartbeat", session.getRemoteSocketAddress() == null ? "unknown" : SystemUtils.getRawAddress(session .getRemoteSocketAddress()) From 6ea521caad0769a2ef1857c5462daee6024c73a4 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Mon, 16 Nov 2015 12:00:40 +0800 Subject: [PATCH 004/207] Added groupId for plugin. --- pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ad3dd10a2..ad14a17d2 100644 --- a/pom.xml +++ b/pom.xml @@ -52,7 +52,7 @@ http://raykrueger.googlecode.com/svn/repository - + @@ -91,6 +91,7 @@ + org.apache.maven.plugins maven-assembly-plugin From 669442757cdd99ab893f7055a7b991a5289fcc9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Wed, 27 Jan 2016 12:12:19 -0800 Subject: [PATCH 005/207] Group dependencies with similar scope together --- pom.xml | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/pom.xml b/pom.xml index ad14a17d2..78cdd550b 100644 --- a/pom.xml +++ b/pom.xml @@ -103,17 +103,23 @@ - - junit - junit - 4.4 - test - org.slf4j slf4j-api 1.7.5 + + org.springframework + spring + 2.5 + provided + + + com.googlecode + hibernate-memcached + 1.2 + provided + log4j log4j @@ -127,16 +133,10 @@ test - org.springframework - spring - 2.5 - provided - - - com.googlecode - hibernate-memcached - 1.2 - provided + junit + junit + 4.4 + test org.easymock From 9d520ccbd4c0eea4b98094ec81ea45a3fd61763c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Wed, 27 Jan 2016 12:19:24 -0800 Subject: [PATCH 006/207] Moved gpg Apache MAven plugin to a profile "release" --- pom.xml | 47 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/pom.xml b/pom.xml index 78cdd550b..46c63dab3 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,6 @@ - + org.sonatype.oss oss-parent @@ -14,6 +15,7 @@ Extreme performance modern memcached client for java http://code.google.com/p/xmemcached/ jar + dennis zhuang @@ -55,19 +57,6 @@ - - org.apache.maven.plugins - maven-gpg-plugin - - - sign-artifacts - verify - - sign - - - - org.apache.maven.plugins maven-javadoc-plugin @@ -91,7 +80,7 @@ - org.apache.maven.plugins + org.apache.maven.plugins maven-assembly-plugin @@ -102,6 +91,7 @@ + org.slf4j @@ -151,6 +141,7 @@ test + @@ -165,4 +156,30 @@ + + + + release + + false + + + + + org.apache.maven.plugins + maven-gpg-plugin + + + sign-artifacts + verify + + sign + + + + + + + + From b97cbb1bd8338c39c114e7cf55ef07e7be07b825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Wed, 27 Jan 2016 14:09:32 -0800 Subject: [PATCH 007/207] Add initial travis configuration --- .travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..b3a78daae --- /dev/null +++ b/.travis.yml @@ -0,0 +1,6 @@ +language: java +jdk: + - oraclejdk8 + - oraclejdk7 + - openjdk6 + From eb9493a3ae5453c870115b1d59196a1bda5a229d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Wed, 27 Jan 2016 14:16:53 -0800 Subject: [PATCH 008/207] hibernate-memcached pulls javax.transaction:jta 1.0.1B which is not available publicly anymore. So overriding it with a more recent version of javax.transaction:jta --- pom.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/pom.xml b/pom.xml index 46c63dab3..c9f21549d 100644 --- a/pom.xml +++ b/pom.xml @@ -109,7 +109,22 @@ hibernate-memcached 1.2 provided + + + javax.transaction + jta + + + + + javax.transaction + jta + 1.1 + + + log4j log4j From 27ce91f2e08be2042bfaa1037981e7b28c3addca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Wed, 27 Jan 2016 14:30:49 -0800 Subject: [PATCH 009/207] Extract hard coded values in pom.xml into properties --- pom.xml | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/pom.xml b/pom.xml index c9f21549d..bf8341b51 100644 --- a/pom.xml +++ b/pom.xml @@ -55,6 +55,20 @@ + + 1.5 + 1.5 + UTF-8 + + 1.7.5 + 2.5 + 1.2 + 1.1 + 1.2.16 + 4.4 + 2.4 + + @@ -74,9 +88,9 @@ org.apache.maven.plugins maven-compiler-plugin - 1.5 - 1.5 - UTF-8 + ${maven.compiler.source} + ${maven.compiler.target} + ${project.build.sourceEncoding} @@ -96,18 +110,18 @@ org.slf4j slf4j-api - 1.7.5 + ${slf4j.version} org.springframework spring - 2.5 + ${spring.version} provided com.googlecode hibernate-memcached - 1.2 + ${hibernate.memcached.version} provided @@ -121,38 +135,38 @@ javax.transaction jta - 1.1 + ${jta.version} log4j log4j - 1.2.16 + ${log4j.version} test org.slf4j slf4j-log4j12 - 1.7.5 + ${slf4j.version} test junit junit - 4.4 + ${junit.version} test org.easymock easymock - 2.4 + ${easymock.version} test org.easymock easymockclassextension - 2.4 + ${easymock.version} test @@ -163,7 +177,7 @@ org.apache.maven.plugins maven-javadoc-plugin - utf-8 + ${project.build.sourceEncoding} utf-8 en_US net.rubyeye.xmemcached.test From 2337661583f0704780ff070a411b8ed2fb95232c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Wed, 27 Jan 2016 14:46:11 -0800 Subject: [PATCH 010/207] Go around the java 8 doclint issue for javadocs --- pom.xml | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bf8341b51..1cc77f5f2 100644 --- a/pom.xml +++ b/pom.xml @@ -59,7 +59,7 @@ 1.5 1.5 UTF-8 - + 1.7.5 2.5 1.2 @@ -81,6 +81,9 @@ jar + + ${javadoc.xdoclint} + @@ -181,12 +184,24 @@ utf-8 en_US net.rubyeye.xmemcached.test + ${javadoc.xdoclint} + + + jdk8 + + [1.8,) + + + -Xdoclint:none + + + release From 4adfafc9a5ec249ffbf9ca16d59741176770c313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Wed, 27 Jan 2016 15:21:05 -0800 Subject: [PATCH 011/207] Enable resource filtering for test properties files --- pom.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pom.xml b/pom.xml index 1cc77f5f2..5427c4499 100644 --- a/pom.xml +++ b/pom.xml @@ -70,6 +70,16 @@ + + + src/test/resources + true + + **/*.properties + + + + org.apache.maven.plugins From 4d82d74f4729190356f70f3d270ccf5d7b5a3110 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Wed, 27 Jan 2016 15:31:51 -0800 Subject: [PATCH 012/207] Drive the value of the test memcached instance through Apache Maven for the following reason: * It can be overriden at runtime without having to modify any file * It will be helpful for integration tests as we can start our own memcached instance and point the tests to it --- pom.xml | 11 +++++++++++ src/test/resources/test.properties | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5427c4499..55a00c51c 100644 --- a/pom.xml +++ b/pom.xml @@ -67,9 +67,12 @@ 1.2.16 4.4 2.4 + + localhost:12000 + src/test/resources @@ -78,6 +81,14 @@ **/*.properties + + src/test/resources + false + + **/*.properties + + + diff --git a/src/test/resources/test.properties b/src/test/resources/test.properties index 1f3dda3cc..4177afd4d 100644 --- a/src/test/resources/test.properties +++ b/src/test/resources/test.properties @@ -1,2 +1,2 @@ -test.memcached.servers=localhost:12000 +test.memcached.servers=${test.memcached.servers} test.kestrel.servers=localhost\:22133 From 85ec6c09f42a34aa0207a30113e43c417810a4f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Wed, 27 Jan 2016 15:36:57 -0800 Subject: [PATCH 013/207] Add memcached to travis so tests can run. Also changes default memcached port used for tests so they can work on travis --- .travis.yml | 3 ++- pom.xml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b3a78daae..23250532d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,4 +3,5 @@ jdk: - oraclejdk8 - oraclejdk7 - openjdk6 - +services: + - memcached diff --git a/pom.xml b/pom.xml index 55a00c51c..f7b5d6e9f 100644 --- a/pom.xml +++ b/pom.xml @@ -68,7 +68,7 @@ 4.4 2.4 - localhost:12000 + localhost:11211 From 2e4c3b80d37c84629a2957bd84b887e1bb394475 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Wed, 27 Jan 2016 15:45:55 -0800 Subject: [PATCH 014/207] Include build status from Travis on top of the README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4951bc67f..1ae513ce7 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +[![Build Status](https://travis-ci.org/bmahe/xmemcached.svg?branch=master)](https://travis-ci.org/bmahe/xmemcached) + ##Introduction XMemcached is a high performance, easy to use blocking multithreaded memcached client in java. From a2ed75952d2adb568abed5bb29fec97be8a4bd83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Wed, 27 Jan 2016 16:19:29 -0800 Subject: [PATCH 015/207] Fix link to Travis to point to the right branch --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1ae513ce7..72ab7cb44 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://travis-ci.org/bmahe/xmemcached.svg?branch=master)](https://travis-ci.org/bmahe/xmemcached) +[![Build Status](https://travis-ci.org/bmahe/xmemcached.svg?branch=tango)](https://travis-ci.org/bmahe/xmemcached) ##Introduction From c1f71293ee42b29151395526b4d0f83133314871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Wed, 27 Jan 2016 17:05:26 -0800 Subject: [PATCH 016/207] src/test/resources/sampleApplicationContext.xml had some harcoded values for the test instance of memcached. This commit makes this configurable as well --- pom.xml | 4 +++- src/test/resources/sampleApplicationContext.xml | 6 +++--- src/test/resources/test.properties | 2 ++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index f7b5d6e9f..ab6deb0a8 100644 --- a/pom.xml +++ b/pom.xml @@ -68,7 +68,9 @@ 4.4 2.4 - localhost:11211 + localhost + 11211 + ${test.memcached.host}:${test.memcached.port} diff --git a/src/test/resources/sampleApplicationContext.xml b/src/test/resources/sampleApplicationContext.xml index 5d7e6135b..26ff1d79c 100644 --- a/src/test/resources/sampleApplicationContext.xml +++ b/src/test/resources/sampleApplicationContext.xml @@ -7,10 +7,10 @@ - localhost + ${test.memcached.host} - 11211 + ${test.memcached.port} @@ -20,7 +20,7 @@ class="net.rubyeye.xmemcached.utils.XMemcachedClientFactoryBean" destroy-method="shutdown"> - localhost:11211 + ${test.memcached.servers} diff --git a/src/test/resources/test.properties b/src/test/resources/test.properties index 4177afd4d..fa3a2525b 100644 --- a/src/test/resources/test.properties +++ b/src/test/resources/test.properties @@ -1,2 +1,4 @@ test.memcached.servers=${test.memcached.servers} +test.memcached.host=${test.memcached.host} +test.memcached.port=${test.memcached.port} test.kestrel.servers=localhost\:22133 From 151575457a2137e35b4d3cfa390e3a16ceb79434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Wed, 27 Jan 2016 17:12:45 -0800 Subject: [PATCH 017/207] Fix "mvn site" due to error "unmappable character for encoding UTF-8" Removed unrecognizable characters --- .../core/impl/ByteBufferCodecFactoryUnitTest.java | 2 +- .../unittest/core/impl/FutureImplUnitTest.java | 2 +- .../unittest/core/impl/FutureLockImplUnitTest.java | 2 +- .../core/impl/TextLineCodecFactoryUnitTest.java | 2 +- .../unittest/nio/impl/MockSelectableChannel.java | 2 +- .../test/unittest/nio/impl/MockSelectionKey.java | 2 +- .../test/unittest/nio/impl/ReactorUnitTest.java | 14 +++++++------- .../unittest/nio/impl/SelectorManagerUnitTest.java | 4 ++-- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/ByteBufferCodecFactoryUnitTest.java b/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/ByteBufferCodecFactoryUnitTest.java index b627c2366..5fe24ad99 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/ByteBufferCodecFactoryUnitTest.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/ByteBufferCodecFactoryUnitTest.java @@ -15,7 +15,7 @@ * * @author boyan * - * @since 1.0, 2009-12-24 ����10:49:54 + * @since 1.0, 2009-12-24 10:49:54 */ public class ByteBufferCodecFactoryUnitTest { diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/FutureImplUnitTest.java b/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/FutureImplUnitTest.java index d598e909a..5f97f1b72 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/FutureImplUnitTest.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/FutureImplUnitTest.java @@ -19,7 +19,7 @@ * * @author boyan * - * @since 1.0, 2009-12-24 ����11:04:22 + * @since 1.0, 2009-12-24 11:04:22 */ public class FutureImplUnitTest { diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/FutureLockImplUnitTest.java b/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/FutureLockImplUnitTest.java index 114d81c2c..aca2b669a 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/FutureLockImplUnitTest.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/FutureLockImplUnitTest.java @@ -19,7 +19,7 @@ * * @author boyan * - * @since 1.0, 2009-12-24 ����11:04:22 + * @since 1.0, 2009-12-24 11:04:22 */ public class FutureLockImplUnitTest { diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/TextLineCodecFactoryUnitTest.java b/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/TextLineCodecFactoryUnitTest.java index a13fd78d9..782ab44f0 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/TextLineCodecFactoryUnitTest.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/TextLineCodecFactoryUnitTest.java @@ -15,7 +15,7 @@ * * @author boyan * - * @since 1.0, 2009-12-24 ����10:33:59 + * @since 1.0, 2009-12-24 10:33:59 */ public class TextLineCodecFactoryUnitTest { diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/MockSelectableChannel.java b/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/MockSelectableChannel.java index 562d0c24a..ec58b38bb 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/MockSelectableChannel.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/MockSelectableChannel.java @@ -14,7 +14,7 @@ * * @author boyan * - * @since 1.0, 2009-12-24 ����01:40:15 + * @since 1.0, 2009-12-24 01:40:15 */ public class MockSelectableChannel extends SelectableChannel { diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/MockSelectionKey.java b/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/MockSelectionKey.java index cb4af5ae1..8a9cbed24 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/MockSelectionKey.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/MockSelectionKey.java @@ -11,7 +11,7 @@ * * @author boyan * - * @since 1.0, 2009-12-24 ����02:01:20 + * @since 1.0, 2009-12-24 02:01:20 */ public class MockSelectionKey extends SelectionKey { diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/ReactorUnitTest.java b/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/ReactorUnitTest.java index 06c925a70..b33eea159 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/ReactorUnitTest.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/ReactorUnitTest.java @@ -27,7 +27,7 @@ * * @author boyan * - * @since 1.0, 2009-12-24 ����01:18:18 + * @since 1.0, 2009-12-24 01:18:18 */ public class ReactorUnitTest { @@ -144,10 +144,10 @@ private void addTimeoutKey(IMocksControl mocksControl, Set allKeys MockSelectionKey key = new MockSelectionKey(); NioSession session = mocksControl.createMock(NioSession.class); key.attach(session); - // �ж�session�Ƿ���ڣ�����Ϊ���� + // �ж�session�Ƿ���ڣ�����Ϊ���� EasyMock.expect(session.isExpired()).andReturn(true); - // ���ھͻ����onSessionExpired�����ر����� - // ͬʱ��expired��session�����ж�idle + // ���ھͻ����onSessionExpired�����ر����� + // ͬʱ��expired��session�����ж�idle session.onEvent(EventType.EXPIRED, this.reactor.getSelector()); EasyMock.expectLastCall(); session.close(); @@ -193,11 +193,11 @@ private void addIdleKey(IMocksControl mocksControl, Set allKeys) { MockSelectionKey key = new MockSelectionKey(); NioSession session = mocksControl.createMock(NioSession.class); key.attach(session); - // �ж�session�Ƿ���ڣ������� + // session EasyMock.expect(session.isExpired()).andReturn(false); - // �����ھͻ��ж�session�Ƿ�idle������idleΪ�� + // session idle EasyMock.expect(session.isIdle()).andReturn(true); - // ���idle����Ϊ�棬��ô�����onSessionIdle + // idle onSessionIdle session.onEvent(EventType.IDLE, this.reactor.getSelector()); EasyMock.expectLastCall(); diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/SelectorManagerUnitTest.java b/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/SelectorManagerUnitTest.java index 3e69d8f96..bb5dd9cd8 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/SelectorManagerUnitTest.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/SelectorManagerUnitTest.java @@ -22,7 +22,7 @@ * * @author boyan * - * @since 1.0, 2009-12-24 ����03:09:42 + * @since 1.0, 2009-12-24 03:09:42 */ public class SelectorManagerUnitTest { @@ -83,7 +83,7 @@ public void testRegisterOpenSession() throws Exception { IMocksControl control = EasyMock.createControl(); NioSession session = control.createMock(NioSession.class); EasyMock.makeThreadSafe(session, true); - // next reactor��index=2 + // next reactor index=2 Reactor nextReactor = this.selectorManager.getReactorByIndex(2); session.onEvent(EventType.ENABLE_READ, nextReactor.getSelector()); EasyMock.expectLastCall(); From 0c2d6e2f8442cc1f7f04f4cdd248e45f9ab4952a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Wed, 27 Jan 2016 17:47:10 -0800 Subject: [PATCH 018/207] Add surefire report --- pom.xml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/pom.xml b/pom.xml index ab6deb0a8..8f5670e54 100644 --- a/pom.xml +++ b/pom.xml @@ -60,6 +60,9 @@ 1.5 UTF-8 + 2.19.1 + 2.1 + 1.7.5 2.5 1.2 @@ -210,6 +213,20 @@ ${javadoc.xdoclint} + + org.apache.maven.plugins + maven-surefire-report-plugin + ${maven.surefire.report.plugin.version} + + false + + + + + org.apache.maven.plugins + maven-jxr-plugin + ${maven.jxr.plugin.version} + From 981c1ad1da86d365fdb2dac3526f3fcf99138ad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Wed, 27 Jan 2016 21:12:06 -0800 Subject: [PATCH 019/207] Add an after_script step to build website --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 23250532d..11aa675fc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,3 +5,5 @@ jdk: - openjdk6 services: - memcached +after_script: + - mvn site From dfbb4d9bf070e907c72696ba5ffc1efc913df6d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Thu, 28 Jan 2016 00:56:48 -0800 Subject: [PATCH 020/207] Ignore Idea files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index becad4593..6ffb77d54 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ target/ .classpath .project .settings +.idea/ +*.iml From b7f9f33dd078cf2d81e0ed2de8c56eed7e5e2410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Thu, 28 Jan 2016 01:14:40 -0800 Subject: [PATCH 021/207] Add travis/Apache Maven configuration to publish the generated site --- .travis.yml | 5 ++++- pom.xml | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 11aa675fc..2da584cf9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,4 +6,7 @@ jdk: services: - memcached after_script: - - mvn site + - mvn site -Ppublish-site-github +env: + global: + secure: f0+kC0wV6hO09ls2X4seMD6bU/EKMUfz6J/2r6qXvS6jflFz9208O8uNecFjm/eicVmZaDCrZDv7eXyi0LS/wRrjw9z2U4gnIQKXx0NfiUYw2TAsURKKYQJiOVXeC3xw9/75m1/Cdz19fgqgmDS1xIFzxqIe0RcyxJpFHjxn3SFHBZBT2ryShE4QERnsbtonEvKbk8kV4UUpVJMwqnMKGjlCIYkkANxUK8S9/3UEit0Ns4gkkwrvwHY+N805EViIHT6/2EK+c7myydsyy6GzEIEAsg/h8fK1TrGC54y7diU1lAcQHsVf2Te9IBYSjr426wRVzubcvUKStsPHEO7XVla7ecAW76YtuXNK/y6X0z3UVNTuyEadzAiDbned7Vp7IfrWLOKm0l+bNrb3wHsEd+XbZk1YEK9xDnj+nt+psqShstSay+JJmgdm+pg17kqgPUgR5QOIkpcEJerR3cEo3T021fgr4Tzd+eXRzNxGUMvvdmHVHKibPiaTnZ2iVoHWeJJT413PGhOsMT1Fnmqj/ET/2gSLfT909nRBidkg8lfymusJAHRDO99gw3QWY/6iMCWc9M99ZpbYK0EysTQbpCcIvnSriPufN2jSeQ5MdHy7OOkEuVpefOBCPfdePsoQLEZSdMj1frKZkPnmc/icEaCOuyQ4mbqFjxhlU9SZ5Rk= diff --git a/pom.xml b/pom.xml index 8f5670e54..092515d0f 100644 --- a/pom.xml +++ b/pom.xml @@ -62,6 +62,7 @@ 2.19.1 2.1 + 0.12 1.7.5 2.5 @@ -265,5 +266,36 @@ + + + publish-site-github + + false + + + github + ${env.GITHUB_OAUTH_TOKEN} + + + + + com.github.github + site-maven-plugin + ${maven.site.maven.plugin.github.version} + + Creating site for ${project.version} + + + + + site + + site + + + + + + From 9d830bb0e29a9f6f0da970734aba05579a5c9360 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Thu, 28 Jan 2016 01:40:55 -0800 Subject: [PATCH 022/207] Update travis configuration for uploading generated website --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2da584cf9..399512853 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ jdk: services: - memcached after_script: - - mvn site -Ppublish-site-github + - mvn site -Ppublish-site-github -Dgithub.site.repositoryName=xmemcached -Dgithub.site.repositoryOwner=bmahe -Dgithub.site.userName=bmahe env: global: secure: f0+kC0wV6hO09ls2X4seMD6bU/EKMUfz6J/2r6qXvS6jflFz9208O8uNecFjm/eicVmZaDCrZDv7eXyi0LS/wRrjw9z2U4gnIQKXx0NfiUYw2TAsURKKYQJiOVXeC3xw9/75m1/Cdz19fgqgmDS1xIFzxqIe0RcyxJpFHjxn3SFHBZBT2ryShE4QERnsbtonEvKbk8kV4UUpVJMwqnMKGjlCIYkkANxUK8S9/3UEit0Ns4gkkwrvwHY+N805EViIHT6/2EK+c7myydsyy6GzEIEAsg/h8fK1TrGC54y7diU1lAcQHsVf2Te9IBYSjr426wRVzubcvUKStsPHEO7XVla7ecAW76YtuXNK/y6X0z3UVNTuyEadzAiDbned7Vp7IfrWLOKm0l+bNrb3wHsEd+XbZk1YEK9xDnj+nt+psqShstSay+JJmgdm+pg17kqgPUgR5QOIkpcEJerR3cEo3T021fgr4Tzd+eXRzNxGUMvvdmHVHKibPiaTnZ2iVoHWeJJT413PGhOsMT1Fnmqj/ET/2gSLfT909nRBidkg8lfymusJAHRDO99gw3QWY/6iMCWc9M99ZpbYK0EysTQbpCcIvnSriPufN2jSeQ5MdHy7OOkEuVpefOBCPfdePsoQLEZSdMj1frKZkPnmc/icEaCOuyQ4mbqFjxhlU9SZ5Rk= From baf360702d351827ca3453e8acc2369579111cb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Thu, 28 Jan 2016 02:00:03 -0800 Subject: [PATCH 023/207] Make git site call in travis more verbose as it is too quiet --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 399512853..811439649 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ jdk: services: - memcached after_script: - - mvn site -Ppublish-site-github -Dgithub.site.repositoryName=xmemcached -Dgithub.site.repositoryOwner=bmahe -Dgithub.site.userName=bmahe + - mvn -X site -Ppublish-site-github -Dgithub.site.repositoryName=xmemcached -Dgithub.site.repositoryOwner=bmahe -Dgithub.site.userName=bmahe env: global: secure: f0+kC0wV6hO09ls2X4seMD6bU/EKMUfz6J/2r6qXvS6jflFz9208O8uNecFjm/eicVmZaDCrZDv7eXyi0LS/wRrjw9z2U4gnIQKXx0NfiUYw2TAsURKKYQJiOVXeC3xw9/75m1/Cdz19fgqgmDS1xIFzxqIe0RcyxJpFHjxn3SFHBZBT2ryShE4QERnsbtonEvKbk8kV4UUpVJMwqnMKGjlCIYkkANxUK8S9/3UEit0Ns4gkkwrvwHY+N805EViIHT6/2EK+c7myydsyy6GzEIEAsg/h8fK1TrGC54y7diU1lAcQHsVf2Te9IBYSjr426wRVzubcvUKStsPHEO7XVla7ecAW76YtuXNK/y6X0z3UVNTuyEadzAiDbned7Vp7IfrWLOKm0l+bNrb3wHsEd+XbZk1YEK9xDnj+nt+psqShstSay+JJmgdm+pg17kqgPUgR5QOIkpcEJerR3cEo3T021fgr4Tzd+eXRzNxGUMvvdmHVHKibPiaTnZ2iVoHWeJJT413PGhOsMT1Fnmqj/ET/2gSLfT909nRBidkg8lfymusJAHRDO99gw3QWY/6iMCWc9M99ZpbYK0EysTQbpCcIvnSriPufN2jSeQ5MdHy7OOkEuVpefOBCPfdePsoQLEZSdMj1frKZkPnmc/icEaCOuyQ4mbqFjxhlU9SZ5Rk= From 4a62ba975f2c721c2036b34bed8ea63e5e908241 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Thu, 28 Jan 2016 02:14:45 -0800 Subject: [PATCH 024/207] Disable site publishing in Travis when executing from a pull request --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 811439649..313db3d2d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ jdk: services: - memcached after_script: - - mvn -X site -Ppublish-site-github -Dgithub.site.repositoryName=xmemcached -Dgithub.site.repositoryOwner=bmahe -Dgithub.site.userName=bmahe + - '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && mvn -X site -Ppublish-site-github -Dgithub.site.repositoryName=xmemcached -Dgithub.site.repositoryOwner=bmahe -Dgithub.site.userName=bmahe || false' env: global: secure: f0+kC0wV6hO09ls2X4seMD6bU/EKMUfz6J/2r6qXvS6jflFz9208O8uNecFjm/eicVmZaDCrZDv7eXyi0LS/wRrjw9z2U4gnIQKXx0NfiUYw2TAsURKKYQJiOVXeC3xw9/75m1/Cdz19fgqgmDS1xIFzxqIe0RcyxJpFHjxn3SFHBZBT2ryShE4QERnsbtonEvKbk8kV4UUpVJMwqnMKGjlCIYkkANxUK8S9/3UEit0Ns4gkkwrvwHY+N805EViIHT6/2EK+c7myydsyy6GzEIEAsg/h8fK1TrGC54y7diU1lAcQHsVf2Te9IBYSjr426wRVzubcvUKStsPHEO7XVla7ecAW76YtuXNK/y6X0z3UVNTuyEadzAiDbned7Vp7IfrWLOKm0l+bNrb3wHsEd+XbZk1YEK9xDnj+nt+psqShstSay+JJmgdm+pg17kqgPUgR5QOIkpcEJerR3cEo3T021fgr4Tzd+eXRzNxGUMvvdmHVHKibPiaTnZ2iVoHWeJJT413PGhOsMT1Fnmqj/ET/2gSLfT909nRBidkg8lfymusJAHRDO99gw3QWY/6iMCWc9M99ZpbYK0EysTQbpCcIvnSriPufN2jSeQ5MdHy7OOkEuVpefOBCPfdePsoQLEZSdMj1frKZkPnmc/icEaCOuyQ4mbqFjxhlU9SZ5Rk= From a4c405cbc2e2924af8a68221a7fb6e4c853fc44f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Thu, 28 Jan 2016 19:53:34 -0800 Subject: [PATCH 025/207] Fix git/scm urls --- .travis.yml | 2 +- pom.xml | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 313db3d2d..e3bf775f4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ jdk: services: - memcached after_script: - - '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && mvn -X site -Ppublish-site-github -Dgithub.site.repositoryName=xmemcached -Dgithub.site.repositoryOwner=bmahe -Dgithub.site.userName=bmahe || false' + - '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && mvn -X site -Ppublish-site-github || false' env: global: secure: f0+kC0wV6hO09ls2X4seMD6bU/EKMUfz6J/2r6qXvS6jflFz9208O8uNecFjm/eicVmZaDCrZDv7eXyi0LS/wRrjw9z2U4gnIQKXx0NfiUYw2TAsURKKYQJiOVXeC3xw9/75m1/Cdz19fgqgmDS1xIFzxqIe0RcyxJpFHjxn3SFHBZBT2ryShE4QERnsbtonEvKbk8kV4UUpVJMwqnMKGjlCIYkkANxUK8S9/3UEit0Ns4gkkwrvwHY+N805EViIHT6/2EK+c7myydsyy6GzEIEAsg/h8fK1TrGC54y7diU1lAcQHsVf2Te9IBYSjr426wRVzubcvUKStsPHEO7XVla7ecAW76YtuXNK/y6X0z3UVNTuyEadzAiDbned7Vp7IfrWLOKm0l+bNrb3wHsEd+XbZk1YEK9xDnj+nt+psqShstSay+JJmgdm+pg17kqgPUgR5QOIkpcEJerR3cEo3T021fgr4Tzd+eXRzNxGUMvvdmHVHKibPiaTnZ2iVoHWeJJT413PGhOsMT1Fnmqj/ET/2gSLfT909nRBidkg8lfymusJAHRDO99gw3QWY/6iMCWc9M99ZpbYK0EysTQbpCcIvnSriPufN2jSeQ5MdHy7OOkEuVpefOBCPfdePsoQLEZSdMj1frKZkPnmc/icEaCOuyQ4mbqFjxhlU9SZ5Rk= diff --git a/pom.xml b/pom.xml index 092515d0f..1ccea2ba8 100644 --- a/pom.xml +++ b/pom.xml @@ -32,9 +32,9 @@ - scm:git:git@github.com:killme2008/xmemcached.git - scm:git:git@github.com:killme2008/xmemcached.git - git@github.com:killme2008/xmemcached.git + scm:git:git://github.com/bmahe/xmemcached.git + scm:git:git@github.com:bmahe/xmemcached.git + https://github.com/bmahe/xmemcached @@ -284,6 +284,7 @@ ${maven.site.maven.plugin.github.version} Creating site for ${project.version} + true From 8956937c8ca0a128b37097a22d0524cea5121967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Thu, 28 Jan 2016 21:40:14 -0800 Subject: [PATCH 026/207] Fix Github token for Apache Maven site upload --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e3bf775f4..63d38857a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,4 +9,4 @@ after_script: - '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && mvn -X site -Ppublish-site-github || false' env: global: - secure: f0+kC0wV6hO09ls2X4seMD6bU/EKMUfz6J/2r6qXvS6jflFz9208O8uNecFjm/eicVmZaDCrZDv7eXyi0LS/wRrjw9z2U4gnIQKXx0NfiUYw2TAsURKKYQJiOVXeC3xw9/75m1/Cdz19fgqgmDS1xIFzxqIe0RcyxJpFHjxn3SFHBZBT2ryShE4QERnsbtonEvKbk8kV4UUpVJMwqnMKGjlCIYkkANxUK8S9/3UEit0Ns4gkkwrvwHY+N805EViIHT6/2EK+c7myydsyy6GzEIEAsg/h8fK1TrGC54y7diU1lAcQHsVf2Te9IBYSjr426wRVzubcvUKStsPHEO7XVla7ecAW76YtuXNK/y6X0z3UVNTuyEadzAiDbned7Vp7IfrWLOKm0l+bNrb3wHsEd+XbZk1YEK9xDnj+nt+psqShstSay+JJmgdm+pg17kqgPUgR5QOIkpcEJerR3cEo3T021fgr4Tzd+eXRzNxGUMvvdmHVHKibPiaTnZ2iVoHWeJJT413PGhOsMT1Fnmqj/ET/2gSLfT909nRBidkg8lfymusJAHRDO99gw3QWY/6iMCWc9M99ZpbYK0EysTQbpCcIvnSriPufN2jSeQ5MdHy7OOkEuVpefOBCPfdePsoQLEZSdMj1frKZkPnmc/icEaCOuyQ4mbqFjxhlU9SZ5Rk= + - secure: by8Y+t+Dt7CShdmPw9vb2ssO2bHl5PKxS6n5VyRI6Jy2cRtCHsVIIMKe/6bJATGSbhzDOCrbQUC9U9WgIkBp8nCbI4UqCF31us+vt+OJXQIX2BT5nyRetsRQ2n2y8ebj7C+LJYfN72W7UaUYLuLXhh3+XfT51NCEppA2Po0LGf3O05yMsMYcuHuXNGitVMx7jZCQS+7FnMNdtsgjDrIzELOZQ65oKjh7uWTBRm6Fw+EZZVmz0wg7O3qrlFpUGQOh9rGUM9/coIMeXqU5ZcnXayXbeaQWO6/UXrTt/xLEupUEWsBm0QJEMGlYvvhpThSSAbkBE0PCWys6Fm7BqCmMOvISCuVlN6h3aUXXkQdpuQEATrLuYx63zJzjIxWlW0wmv4a1iB1+gCBtK67N4lD/sgv+6WPDCz3JAPulLTtCbaqoHJ0+VKkvZtsLBUDapRqe2FcVV+wsKMCdEx/gyhvwHwam0szenRmm3khwP7hoTX3v6VNuBE/C/sM9mysDim9nAovDvcJC1hA8mfQDnCi0WCHVF6FJnaydQxPEb6JxB3QCryxYlB6kT+pjEthXZiCxwLOnylVWANYkDVuhhi62p0x/Dvu50skroXflbd+YlExYZEfnhIo0GQ+ByLSGAbVxiuKqUYEMoJGReKdjc4HE/N6oCwdJ1dICKyU18SssWLk= From 2c84ac4e811a33da68399793d468c56cf41c7eef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Fri, 29 Jan 2016 01:28:53 -0800 Subject: [PATCH 027/207] Use a more recent skin for the Apache Maven site --- src/site/site.xml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/site/site.xml diff --git a/src/site/site.xml b/src/site/site.xml new file mode 100644 index 000000000..58c76b4de --- /dev/null +++ b/src/site/site.xml @@ -0,0 +1,31 @@ + + + org.apache.maven.skins + maven-fluido-skin + 1.4 + + + + false + true + + true + + + bmahe/xmemcached + right + green + + + + + + XMemcached + # + + + + + + + From 61cf9b95fe8de3c72d5e037413bddb642b242f67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Fri, 29 Jan 2016 01:29:14 -0800 Subject: [PATCH 028/207] Git ignore temp files from vim: *.swp --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 6ffb77d54..c589a0970 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ target/ .settings .idea/ *.iml +*.swp From 0a8dd9c4871c6e239cde5f389e2a4b99872a2dfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Fri, 29 Jan 2016 12:19:51 -0800 Subject: [PATCH 029/207] Parametrized github account name with a new Apache Maven property: "github.account". This is used in the scm connections as well as references to the repository location in site.xml --- pom.xml | 8 +++++--- src/site/site.xml | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 1ccea2ba8..d6d680dc1 100644 --- a/pom.xml +++ b/pom.xml @@ -32,9 +32,9 @@ - scm:git:git://github.com/bmahe/xmemcached.git - scm:git:git@github.com:bmahe/xmemcached.git - https://github.com/bmahe/xmemcached + scm:git:git://github.com/${github.account}/xmemcached.git + scm:git:git@github.com:${github.account}/xmemcached.git + https://github.com/${github.account}/xmemcached @@ -56,6 +56,8 @@ + bmahe + 1.5 1.5 UTF-8 diff --git a/src/site/site.xml b/src/site/site.xml index 58c76b4de..7b557d8b4 100644 --- a/src/site/site.xml +++ b/src/site/site.xml @@ -12,7 +12,7 @@ true - bmahe/xmemcached + ${github.account}/xmemcached right green From d046225b70787221c2e8e8cbc886114df77926b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Mon, 25 Jan 2016 18:25:38 -0800 Subject: [PATCH 030/207] Make cas0 throw a more specific exception when there is no value. This is useful when a key happens to have expired in between calls --- .../rubyeye/xmemcached/XMemcachedClient.java | 5 ++- .../exception/NoValueException.java | 38 +++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 src/main/java/net/rubyeye/xmemcached/exception/NoValueException.java diff --git a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java index ceffba136..9353a5bba 100644 --- a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java +++ b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java @@ -44,6 +44,7 @@ import net.rubyeye.xmemcached.command.ServerAddressAware; import net.rubyeye.xmemcached.command.TextCommandFactory; import net.rubyeye.xmemcached.exception.MemcachedException; +import net.rubyeye.xmemcached.exception.NoValueException; import net.rubyeye.xmemcached.impl.ArrayMemcachedSessionLocator; import net.rubyeye.xmemcached.impl.ClosedMemcachedTCPSession; import net.rubyeye.xmemcached.impl.DefaultKeyProvider; @@ -1702,7 +1703,7 @@ private final boolean cas0(final String key, final int exp, int tryCount = 0; GetsResponse result = getsResponse; if (result == null) { - throw new MemcachedException("Null GetsResponse"); + throw new NoValueException("Null GetsResponse for key=" + key); } while (tryCount <= operation.getMaxTries() && result != null @@ -1716,7 +1717,7 @@ private final boolean cas0(final String key, final int exp, tryCount++; result = this.gets0(key, keyBytes, transcoder); if (result == null) { - throw new MemcachedException( + throw new NoValueException( "could not gets the value for Key=" + key + " for cas"); } if (tryCount > operation.getMaxTries()) { diff --git a/src/main/java/net/rubyeye/xmemcached/exception/NoValueException.java b/src/main/java/net/rubyeye/xmemcached/exception/NoValueException.java new file mode 100644 index 000000000..753143993 --- /dev/null +++ b/src/main/java/net/rubyeye/xmemcached/exception/NoValueException.java @@ -0,0 +1,38 @@ +/** + *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] + *Licensed 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 net.rubyeye.xmemcached.exception; + +/** + * Memcached Client Exception + * @author bmahe + * + */ +public class NoValueException extends MemcachedClientException { + + public NoValueException() { + super(); + } + + public NoValueException(String s) { + super(s); + } + + public NoValueException(String message, Throwable cause) { + super(message, cause); + } + + public NoValueException(Throwable cause) { + super(cause); + } + + private static final long serialVersionUID = -8717259791309127913L; +} From ac5aa0ba39b0764acfc610b31a685fdcae5eb301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Fri, 29 Jan 2016 16:02:31 -0800 Subject: [PATCH 031/207] Add more reports to the Apache Maven site --- pom.xml | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d6d680dc1..9d390f73c 100644 --- a/pom.xml +++ b/pom.xml @@ -62,9 +62,17 @@ 1.5 UTF-8 - 2.19.1 + 2.6 + 2.10 + 2.10 + 3.0.1 2.1 + 3.0.1 + 2.7 0.12 + 2.19.1 + 2.4 + 2.1 1.7.5 2.5 @@ -230,6 +238,82 @@ maven-jxr-plugin ${maven.jxr.plugin.version} + + org.apache.maven.plugins + maven-project-info-reports-plugin + ${maven.project.info.plugin.version} + + + org.apache.maven.plugins + maven-dependency-plugin + ${maven.dependency.plugin.version} + + + + analyze-report + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + ${maven-checkstyle-plugin} + + + org.apache.maven.plugins + maven-pmd-plugin + ${maven-pmd-plugin} + + true + ${project.build.sourceEncoding} + ${maven.compiler.target} + + + + org.codehaus.mojo + findbugs-maven-plugin + ${maven.findbugs.report.plugin} + + + org.codehaus.mojo + cobertura-maven-plugin + ${cobertura-maven-plugin} + + + + cobertura + + cobertura + + + true + + + + + + org.codehaus.mojo + taglist-maven-plugin + ${maven.taglist.report.plugin} + + true + + + + org.codehaus.mojo + versions-maven-plugin + ${maven.versions.plugin} + + + + dependency-updates-report + plugin-updates-report + property-updates-report + + + + From ea2b75ef5a97540d7ba3043d8552714209da4149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Fri, 29 Jan 2016 17:33:16 -0800 Subject: [PATCH 032/207] Reduce logging and redirect test output to a file per test. This will reduce verbosity of the build as well as organizing logs per test --- pom.xml | 10 ++++++++++ src/test/resources/log4j.properties | 5 ++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 9d390f73c..f1b02c2c4 100644 --- a/pom.xml +++ b/pom.xml @@ -70,6 +70,7 @@ 3.0.1 2.7 0.12 + 2.19.1 2.19.1 2.4 2.1 @@ -133,6 +134,15 @@ ${project.build.sourceEncoding} + + org.apache.maven.plugins + maven-surefire-plugin + ${maven.surefire.plugin.version} + + true + + + org.apache.maven.plugins maven-assembly-plugin diff --git a/src/test/resources/log4j.properties b/src/test/resources/log4j.properties index 7184ac2e5..f90d3b068 100644 --- a/src/test/resources/log4j.properties +++ b/src/test/resources/log4j.properties @@ -1,6 +1,5 @@ log4j.rootLogger=INFO,CONSOLE +log4j.appender.Threshold=INFO log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender -log4j.appender.Threshold=WARN -log4j.appender.CONSOLE.Target=System.out log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout -log4j.appender.CONSOLE.layout.ConversionPattern=[%-5p]%d{yyyy-MM-dd HH:mm:ssS} %c %m%n \ No newline at end of file +log4j.appender.CONSOLE.layout.ConversionPattern=[%-5p]%d{yyyy-MM-dd HH:mm:ssS} %c %m%n From 1b623a354d76490dcde365071c666eb2c080c41d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Fri, 29 Jan 2016 17:59:32 -0800 Subject: [PATCH 033/207] Travis build was failing because the output is too long. Therefore making the build less verbose and using travis_wait so it does not time out while waiting for the upload to github --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 63d38857a..7a898a3a4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ jdk: services: - memcached after_script: - - '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && mvn -X site -Ppublish-site-github || false' + - '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && travis_wait mvn site -Ppublish-site-github || false' env: global: - secure: by8Y+t+Dt7CShdmPw9vb2ssO2bHl5PKxS6n5VyRI6Jy2cRtCHsVIIMKe/6bJATGSbhzDOCrbQUC9U9WgIkBp8nCbI4UqCF31us+vt+OJXQIX2BT5nyRetsRQ2n2y8ebj7C+LJYfN72W7UaUYLuLXhh3+XfT51NCEppA2Po0LGf3O05yMsMYcuHuXNGitVMx7jZCQS+7FnMNdtsgjDrIzELOZQ65oKjh7uWTBRm6Fw+EZZVmz0wg7O3qrlFpUGQOh9rGUM9/coIMeXqU5ZcnXayXbeaQWO6/UXrTt/xLEupUEWsBm0QJEMGlYvvhpThSSAbkBE0PCWys6Fm7BqCmMOvISCuVlN6h3aUXXkQdpuQEATrLuYx63zJzjIxWlW0wmv4a1iB1+gCBtK67N4lD/sgv+6WPDCz3JAPulLTtCbaqoHJ0+VKkvZtsLBUDapRqe2FcVV+wsKMCdEx/gyhvwHwam0szenRmm3khwP7hoTX3v6VNuBE/C/sM9mysDim9nAovDvcJC1hA8mfQDnCi0WCHVF6FJnaydQxPEb6JxB3QCryxYlB6kT+pjEthXZiCxwLOnylVWANYkDVuhhi62p0x/Dvu50skroXflbd+YlExYZEfnhIo0GQ+ByLSGAbVxiuKqUYEMoJGReKdjc4HE/N6oCwdJ1dICKyU18SssWLk= From aef3118580a9ac5d296c638ff4a92e326a4501cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Fri, 29 Jan 2016 18:36:38 -0800 Subject: [PATCH 034/207] Set travis timeout to 5 hours --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7a898a3a4..5ceb503d2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ jdk: services: - memcached after_script: - - '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && travis_wait mvn site -Ppublish-site-github || false' + - '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && travis_wait 300 mvn site -Ppublish-site-github || false' env: global: - secure: by8Y+t+Dt7CShdmPw9vb2ssO2bHl5PKxS6n5VyRI6Jy2cRtCHsVIIMKe/6bJATGSbhzDOCrbQUC9U9WgIkBp8nCbI4UqCF31us+vt+OJXQIX2BT5nyRetsRQ2n2y8ebj7C+LJYfN72W7UaUYLuLXhh3+XfT51NCEppA2Po0LGf3O05yMsMYcuHuXNGitVMx7jZCQS+7FnMNdtsgjDrIzELOZQ65oKjh7uWTBRm6Fw+EZZVmz0wg7O3qrlFpUGQOh9rGUM9/coIMeXqU5ZcnXayXbeaQWO6/UXrTt/xLEupUEWsBm0QJEMGlYvvhpThSSAbkBE0PCWys6Fm7BqCmMOvISCuVlN6h3aUXXkQdpuQEATrLuYx63zJzjIxWlW0wmv4a1iB1+gCBtK67N4lD/sgv+6WPDCz3JAPulLTtCbaqoHJ0+VKkvZtsLBUDapRqe2FcVV+wsKMCdEx/gyhvwHwam0szenRmm3khwP7hoTX3v6VNuBE/C/sM9mysDim9nAovDvcJC1hA8mfQDnCi0WCHVF6FJnaydQxPEb6JxB3QCryxYlB6kT+pjEthXZiCxwLOnylVWANYkDVuhhi62p0x/Dvu50skroXflbd+YlExYZEfnhIo0GQ+ByLSGAbVxiuKqUYEMoJGReKdjc4HE/N6oCwdJ1dICKyU18SssWLk= From 3abe333003cc785e826c53a554509d5575ce0dcb Mon Sep 17 00:00:00 2001 From: Ayman Abdel Ghany Date: Tue, 2 Feb 2016 04:18:15 +0200 Subject: [PATCH 035/207] -squid:S1244 Fixing the imprecise floating point numbers comparison -squid:S1444 adding final keyword --- .../java/com/google/code/yanf4j/config/Configuration.java | 2 +- .../com/google/code/yanf4j/core/impl/PoolDispatcher.java | 4 ++-- .../java/net/rubyeye/xmemcached/transcoders/CachedData.java | 2 +- .../java/net/rubyeye/xmemcached/helper/AbstractChecker.java | 5 +++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/google/code/yanf4j/config/Configuration.java b/src/main/java/com/google/code/yanf4j/config/Configuration.java index e0c69b152..0cc9d9a89 100644 --- a/src/main/java/com/google/code/yanf4j/config/Configuration.java +++ b/src/main/java/com/google/code/yanf4j/config/Configuration.java @@ -70,7 +70,7 @@ public class Configuration { /** * Max read buffer size for connection */ - public static int MAX_READ_BUFFER_SIZE = 128 * 1024; + public final static int MAX_READ_BUFFER_SIZE = 128 * 1024; /** * check session idle interval diff --git a/src/main/java/com/google/code/yanf4j/core/impl/PoolDispatcher.java b/src/main/java/com/google/code/yanf4j/core/impl/PoolDispatcher.java index 2bf906c72..8f80d55d0 100644 --- a/src/main/java/com/google/code/yanf4j/core/impl/PoolDispatcher.java +++ b/src/main/java/com/google/code/yanf4j/core/impl/PoolDispatcher.java @@ -40,8 +40,8 @@ * */ public class PoolDispatcher implements Dispatcher { - public static int POOL_QUEUE_SIZE_FACTOR = 1000; - public static float MAX_POOL_SIZE_FACTOR = 1.25f; + public static final int POOL_QUEUE_SIZE_FACTOR = 1000; + public static final float MAX_POOL_SIZE_FACTOR = 1.25f; private ThreadPoolExecutor threadPool; public PoolDispatcher(int poolSize) { diff --git a/src/main/java/net/rubyeye/xmemcached/transcoders/CachedData.java b/src/main/java/net/rubyeye/xmemcached/transcoders/CachedData.java index 7b590e8b1..78ffe73ad 100644 --- a/src/main/java/net/rubyeye/xmemcached/transcoders/CachedData.java +++ b/src/main/java/net/rubyeye/xmemcached/transcoders/CachedData.java @@ -13,7 +13,7 @@ public final class CachedData { /** * Maximum data size allowed by memcached. */ - public static int MAX_SIZE = 1024 * 1024; + public final static int MAX_SIZE = 1024 * 1024; protected int flag; protected long cas; diff --git a/src/test/java/net/rubyeye/xmemcached/helper/AbstractChecker.java b/src/test/java/net/rubyeye/xmemcached/helper/AbstractChecker.java index 19cace58b..53d73c8c0 100644 --- a/src/test/java/net/rubyeye/xmemcached/helper/AbstractChecker.java +++ b/src/test/java/net/rubyeye/xmemcached/helper/AbstractChecker.java @@ -5,6 +5,7 @@ public abstract class AbstractChecker implements ExceptionChecker { + private static final double EPSILON = 0.00000001; public void call() throws Exception { // TODO Auto-generated method stub @@ -108,7 +109,7 @@ static public void assertEquals(String message, double expected, // NaN and the // the following test fails if (Double.isInfinite(expected)) { - if (!(expected == actual)) + if (!(Math.abs(expected - actual) <= EPSILON)) failNotEquals(message, new Double(expected), new Double(actual)); } else if (!(Math.abs(expected - actual) <= delta)) // Because // comparison with @@ -136,7 +137,7 @@ static public void assertEquals(String message, float expected, // NaN and the // the following test fails if (Float.isInfinite(expected)) { - if (!(expected == actual)) + if (!(Math.abs(expected - actual) <= EPSILON)) failNotEquals(message, new Float(expected), new Float(actual)); } else if (!(Math.abs(expected - actual) <= delta)) failNotEquals(message, new Float(expected), new Float(actual)); From 3b4d413730791cf4da9f07861093612da81b0b07 Mon Sep 17 00:00:00 2001 From: Ayman Abdel Ghany Date: Thu, 4 Feb 2016 16:18:34 +0200 Subject: [PATCH 036/207] Using Log instead of Throwable.printStackTrace(...) --- .../rubyeye/memcached/BaseReadWriteThread.java | 3 ++- .../result_analyse/ResultAnalyser.java | 12 +++++++----- .../unittest/core/impl/FutureImplUnitTest.java | 16 +++++++++------- .../example/BinaryProtocolExample.java | 15 +++++++++------ .../rubyeye/xmemcached/example/CASExample.java | 8 +++++++- .../example/MemcachedStateListenerExample.java | 13 ++++++++++--- .../xmemcached/example/SASLExample.java | 17 +++++++++-------- .../xmemcached/example/SimpleExample.java | 18 ++++++++++-------- 8 files changed, 63 insertions(+), 39 deletions(-) diff --git a/benchmark/src/net/rubyeye/memcached/BaseReadWriteThread.java b/benchmark/src/net/rubyeye/memcached/BaseReadWriteThread.java index ec6c56226..ee53cd375 100644 --- a/benchmark/src/net/rubyeye/memcached/BaseReadWriteThread.java +++ b/benchmark/src/net/rubyeye/memcached/BaseReadWriteThread.java @@ -8,6 +8,7 @@ public abstract class BaseReadWriteThread extends Thread { + private static final Logger log = LoggerFactory.getLogger(BaseReadWriteThread.class); protected int repeats; protected CyclicBarrier barrier; protected int offset; @@ -64,7 +65,7 @@ public void run() { barrier.await(); } catch (Exception e) { - e.printStackTrace(); + log.error(e.getMessage(), e); } } diff --git a/benchmark/src/net/rubyeye/memcached/benchmark/result_analyse/ResultAnalyser.java b/benchmark/src/net/rubyeye/memcached/benchmark/result_analyse/ResultAnalyser.java index 891857934..aad8521af 100644 --- a/benchmark/src/net/rubyeye/memcached/benchmark/result_analyse/ResultAnalyser.java +++ b/benchmark/src/net/rubyeye/memcached/benchmark/result_analyse/ResultAnalyser.java @@ -40,6 +40,7 @@ */ public class ResultAnalyser { + private static final Logger log = LoggerFactory.getLogger(ResultAnalyser.class); private static final int HEIGHT = 600; private static final String DEFAULT_RESULT_IMAGES_DIR = "result/images"; private static final String DEFAULT_RESULT_DIR = "result"; @@ -251,15 +252,16 @@ public static void saveAsFile(JFreeChart chart, String outputPath, ChartUtilities.writeChartAsJPEG(out, chart, weight, height); out.flush(); } catch (FileNotFoundException e) { - e.printStackTrace(); + log.error(e.getMessage(), e); } catch (IOException e) { - e.printStackTrace(); + log.error(e.getMessage(), e); } finally { if (out != null) { try { out.close(); } catch (IOException e) { // do nothing + log.error(e.getMessage(), e); } } } @@ -285,8 +287,8 @@ public static JFreeChart createChart(CategoryDataset categoryDataset, render.setSeriesPaint(2, Color.YELLOW); render.setSeriesPaint(3, Color.BLUE); render.setSeriesPaint(4, Color.CYAN); - render.setShapesFilled(Boolean.TRUE);// �����ݵ���ʾʵ�ĵ�Сͼ�� - render.setShapesVisible(true);// ������ʾСͼ�� + render.setShapesFilled(Boolean.TRUE);// �����ݵ���ʾʵ�ĵ�Сͼ�� + render.setShapesVisible(true);// ������ʾСͼ�� CategoryAxis cateaxis = plot.getDomainAxis(); @@ -305,7 +307,7 @@ public static JFreeChart createChart(CategoryDataset categoryDataset, } /** - * ����CategoryDataset���� + * ����CategoryDataset���� * */ public static CategoryDataset createDataset(String[] rowKeys, diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/FutureImplUnitTest.java b/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/FutureImplUnitTest.java index 5f97f1b72..dca4d7571 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/FutureImplUnitTest.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/FutureImplUnitTest.java @@ -1,17 +1,17 @@ package com.google.code.yanf4j.test.unittest.core.impl; +import com.google.code.yanf4j.core.impl.FutureImpl; +import junit.framework.Assert; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.IOException; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import junit.framework.Assert; - -import org.junit.Test; - -import com.google.code.yanf4j.core.impl.FutureImpl; - /** * @@ -24,6 +24,8 @@ public class FutureImplUnitTest { + private static final Logger log = LoggerFactory.getLogger(FutureImplUnitTest.class); + private static final class NotifyFutureRunner implements Runnable { FutureImpl future; long sleepTime; @@ -105,7 +107,7 @@ public void run() { future.cancel(true); } catch (Exception e) { - e.printStackTrace(); + log.error(e.getMessage(), e); } } }).start(); diff --git a/src/test/java/net/rubyeye/xmemcached/example/BinaryProtocolExample.java b/src/test/java/net/rubyeye/xmemcached/example/BinaryProtocolExample.java index 01f67fe70..350fb9d64 100644 --- a/src/test/java/net/rubyeye/xmemcached/example/BinaryProtocolExample.java +++ b/src/test/java/net/rubyeye/xmemcached/example/BinaryProtocolExample.java @@ -9,6 +9,8 @@ import net.rubyeye.xmemcached.exception.MemcachedException; import net.rubyeye.xmemcached.utils.AddrUtil; import net.rubyeye.xmemcached.command.BinaryCommandFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Simple example for xmemcached,use binary protocol @@ -17,6 +19,9 @@ * */ public class BinaryProtocolExample { + + private static final Logger log = LoggerFactory.getLogger(BinaryProtocolExample.class); + public static void main(String[] args) { if (args.length < 1) { System.err.println("Useage:java BinaryProtocolExample [servers]"); @@ -40,19 +45,17 @@ public static void main(String[] args) { value = memcachedClient.get("a"); System.out.println("after delete,a=" + value); } catch (MemcachedException e) { - System.err.println("MemcachedClient operation fail"); - e.printStackTrace(); + log.error("MemcachedClient operation fail", e); } catch (TimeoutException e) { - System.err.println("MemcachedClient operation timeout"); - e.printStackTrace(); + log.error("MemcachedClient operation timeout", e); } catch (InterruptedException e) { // ignore + log.info(e.getMessage()); } try { memcachedClient.shutdown(); } catch (Exception e) { - System.err.println("Shutdown MemcachedClient fail"); - e.printStackTrace(); + log.error("Shutdown MemcachedClient fail", e); } } diff --git a/src/test/java/net/rubyeye/xmemcached/example/CASExample.java b/src/test/java/net/rubyeye/xmemcached/example/CASExample.java index 9a680c976..ebb75e4e0 100644 --- a/src/test/java/net/rubyeye/xmemcached/example/CASExample.java +++ b/src/test/java/net/rubyeye/xmemcached/example/CASExample.java @@ -19,6 +19,8 @@ import net.rubyeye.xmemcached.XMemcachedClientBuilder; import net.rubyeye.xmemcached.command.BinaryCommandFactory; import net.rubyeye.xmemcached.utils.AddrUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * CASOperation example @@ -26,6 +28,10 @@ * @author dennis */ class CASThread extends Thread { + + + private static final Logger log = LoggerFactory.getLogger(CASThread.class); + /** * Increase Operation * @@ -61,7 +67,7 @@ public void run() { this.cd.countDown(); } } catch (Exception e) { - e.printStackTrace(); + log.error(e.getMessage(), e); } } } diff --git a/src/test/java/net/rubyeye/xmemcached/example/MemcachedStateListenerExample.java b/src/test/java/net/rubyeye/xmemcached/example/MemcachedStateListenerExample.java index 51afa5f4d..552d6dcc2 100644 --- a/src/test/java/net/rubyeye/xmemcached/example/MemcachedStateListenerExample.java +++ b/src/test/java/net/rubyeye/xmemcached/example/MemcachedStateListenerExample.java @@ -8,9 +8,13 @@ import net.rubyeye.xmemcached.MemcachedClientStateListener; import net.rubyeye.xmemcached.XMemcachedClientBuilder; import net.rubyeye.xmemcached.utils.AddrUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; class MyListener implements MemcachedClientStateListener { + private static final Logger log = LoggerFactory.getLogger(MyListener.class); + public void onConnected(MemcachedClient memcachedClient, InetSocketAddress inetSocketAddress) { System.out.println("Connect to " + inetSocketAddress); @@ -23,7 +27,7 @@ public void onDisconnected(MemcachedClient memcachedClient, } public void onException(MemcachedClient memcachedClient, Throwable throwable) { - throwable.printStackTrace(); + log.error(throwable.getMessage(), throwable); } @@ -40,6 +44,9 @@ public void onStarted(MemcachedClient memcachedClient) { } public class MemcachedStateListenerExample { + + private static final Logger log = LoggerFactory.getLogger(MemcachedStateListenerExample.class); + public static void main(String[] args) { if (args.length < 1) { System.err @@ -50,7 +57,7 @@ public static void main(String[] args) { try { memcachedClient.shutdown(); } catch (IOException e) { - e.printStackTrace(); + log.error(e.getMessage(), e); } } @@ -64,7 +71,7 @@ public static MemcachedClient getMemcachedClient(String servers) { return builder.build(); } catch (IOException e) { System.err.println("Create MemcachedClient fail"); - e.printStackTrace(); + log.error(e.getMessage(), e); } return null; } diff --git a/src/test/java/net/rubyeye/xmemcached/example/SASLExample.java b/src/test/java/net/rubyeye/xmemcached/example/SASLExample.java index 41daff539..0d9e044fc 100644 --- a/src/test/java/net/rubyeye/xmemcached/example/SASLExample.java +++ b/src/test/java/net/rubyeye/xmemcached/example/SASLExample.java @@ -16,6 +16,8 @@ import net.rubyeye.xmemcached.utils.AddrUtil; import net.rubyeye.xmemcached.auth.AuthInfo; import net.rubyeye.xmemcached.command.BinaryCommandFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Simple example for xmemcached,use binary protocol @@ -24,6 +26,9 @@ * */ public class SASLExample { + + private static final Logger log = LoggerFactory.getLogger(SASLExample.class); + public static void main(String[] args) { if (args.length < 3) { System.err @@ -49,19 +54,16 @@ public static void main(String[] args) { value = memcachedClient.get("a"); System.out.println("after delete,a=" + value); } catch (MemcachedException e) { - System.err.println("MemcachedClient operation fail"); - e.printStackTrace(); + log.error("MemcachedClient operation fail", e); } catch (TimeoutException e) { - System.err.println("MemcachedClient operation timeout"); - e.printStackTrace(); + log.error("MemcachedClient operation timeout", e); } catch (InterruptedException e) { // ignore } try { memcachedClient.shutdown(); } catch (Exception e) { - System.err.println("Shutdown MemcachedClient fail"); - e.printStackTrace(); + log.error("Shutdown MemcachedClient fail", e); } } @@ -76,8 +78,7 @@ public static MemcachedClient getMemcachedClient(String servers, builder.setCommandFactory(new BinaryCommandFactory()); return builder.build(); } catch (IOException e) { - System.err.println("Create MemcachedClient fail"); - e.printStackTrace(); + log.error("Create MemcachedClient fail", e); } return null; } diff --git a/src/test/java/net/rubyeye/xmemcached/example/SimpleExample.java b/src/test/java/net/rubyeye/xmemcached/example/SimpleExample.java index bfb916ec8..643d1b0a2 100644 --- a/src/test/java/net/rubyeye/xmemcached/example/SimpleExample.java +++ b/src/test/java/net/rubyeye/xmemcached/example/SimpleExample.java @@ -9,6 +9,8 @@ import net.rubyeye.xmemcached.XMemcachedClientBuilder; import net.rubyeye.xmemcached.exception.MemcachedException; import net.rubyeye.xmemcached.utils.AddrUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Simple example for xmemcached @@ -17,6 +19,9 @@ * */ public class SimpleExample { + + private static final Logger log = LoggerFactory.getLogger(SimpleExample.class); + public static void main(String[] args) { if (args.length < 1) { System.err.println("Useage:java SimpleExample [servers]"); @@ -53,19 +58,17 @@ public static void main(String[] args) { System.out.println(memcachedClient.touch("b", 1000)); } catch (MemcachedException e) { - System.err.println("MemcachedClient operation fail"); - e.printStackTrace(); + log.error("MemcachedClient operation fail", e); } catch (TimeoutException e) { - System.err.println("MemcachedClient operation timeout"); - e.printStackTrace(); + log.error("MemcachedClient operation timeout", e); } catch (InterruptedException e) { // ignore + log.info(e.getMessage()); } try { memcachedClient.shutdown(); } catch (Exception e) { - System.err.println("Shutdown MemcachedClient fail"); - e.printStackTrace(); + log.error("Shutdown MemcachedClient fail", e); } } @@ -76,8 +79,7 @@ public static MemcachedClient getMemcachedClient(String servers) { AddrUtil.getAddresses(servers)); return builder.build(); } catch (IOException e) { - System.err.println("Create MemcachedClient fail"); - e.printStackTrace(); + log.error("Create MemcachedClient fail", e); } return null; } From 0c1d55ccc6ecd7a23e85e748f9d93c7d5dca218d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Mon, 1 Feb 2016 12:25:51 -0800 Subject: [PATCH 037/207] Fix missing final. This was reported from findbugs --- .../code/yanf4j/core/impl/PoolDispatcher.java | 20 +-- .../core/impl/PoolDispatcherUnitTest.java | 137 +++++++----------- 2 files changed, 67 insertions(+), 90 deletions(-) diff --git a/src/main/java/com/google/code/yanf4j/core/impl/PoolDispatcher.java b/src/main/java/com/google/code/yanf4j/core/impl/PoolDispatcher.java index 8f80d55d0..9224f4d59 100644 --- a/src/main/java/com/google/code/yanf4j/core/impl/PoolDispatcher.java +++ b/src/main/java/com/google/code/yanf4j/core/impl/PoolDispatcher.java @@ -40,22 +40,24 @@ * */ public class PoolDispatcher implements Dispatcher { - public static final int POOL_QUEUE_SIZE_FACTOR = 1000; - public static final float MAX_POOL_SIZE_FACTOR = 1.25f; + public static final int DEFAULT_POOL_QUEUE_SIZE_FACTOR = 1000; + public static final float DEFAULT_MAX_POOL_SIZE_FACTOR = 1.25f; private ThreadPoolExecutor threadPool; public PoolDispatcher(int poolSize) { - this(poolSize, 60, TimeUnit.SECONDS, - new ThreadPoolExecutor.AbortPolicy(), "pool-dispatcher"); + this(poolSize, 60, TimeUnit.SECONDS, new ThreadPoolExecutor.AbortPolicy(), "pool-dispatcher"); } public PoolDispatcher(int poolSize, long keepAliveTime, TimeUnit unit, RejectedExecutionHandler rejectedExecutionHandler, String prefix) { - this.threadPool = new ThreadPoolExecutor(poolSize, - (int) (MAX_POOL_SIZE_FACTOR * poolSize), keepAliveTime, unit, - new ArrayBlockingQueue(poolSize - * POOL_QUEUE_SIZE_FACTOR), new WorkerThreadFactory( - prefix)); + this(poolSize, DEFAULT_POOL_QUEUE_SIZE_FACTOR, DEFAULT_MAX_POOL_SIZE_FACTOR, keepAliveTime, unit, + rejectedExecutionHandler, prefix); + } + + public PoolDispatcher(int poolSize, int poolQueueSizeFactor, float maxPoolSizeFactor, long keepAliveTime, + TimeUnit unit, RejectedExecutionHandler rejectedExecutionHandler, String prefix) { + this.threadPool = new ThreadPoolExecutor(poolSize, (int) (maxPoolSizeFactor * poolSize), keepAliveTime, unit, + new ArrayBlockingQueue(poolSize * poolQueueSizeFactor), new WorkerThreadFactory(prefix)); this.threadPool.setRejectedExecutionHandler(rejectedExecutionHandler); } diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/PoolDispatcherUnitTest.java b/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/PoolDispatcherUnitTest.java index 79efb73b4..6cb5fb765 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/PoolDispatcherUnitTest.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/PoolDispatcherUnitTest.java @@ -11,7 +11,6 @@ import com.google.code.yanf4j.core.impl.PoolDispatcher; - /** * * @@ -22,94 +21,70 @@ */ public class PoolDispatcherUnitTest { - PoolDispatcher dispatcher; - - - @Before - public void setUp() { - this.dispatcher = new PoolDispatcher(10, 60, TimeUnit.SECONDS, new ThreadPoolExecutor.AbortPolicy(),"test"); - } - - private static final class TestRunner implements Runnable { - boolean ran; - - - public void run() { - this.ran = true; + PoolDispatcher dispatcher; - } - } + @Before + public void setUp() { + this.dispatcher = new PoolDispatcher(10, 60, TimeUnit.SECONDS, new ThreadPoolExecutor.AbortPolicy(), "test"); + } + @After + public void tearDown() { + this.dispatcher.stop(); + } - @Test - public void testDispatch() throws Exception { - TestRunner runner = new TestRunner(); - this.dispatcher.dispatch(runner); - Thread.sleep(1000); - Assert.assertTrue(runner.ran); + private static final class TestRunner implements Runnable { + boolean ran; - } + public void run() { + this.ran = true; + } + } - @Test - public void testDispatchNull() throws Exception { - try { - this.dispatcher.dispatch(null); - Assert.fail(); - } - catch (NullPointerException e) { + @Test + public void testDispatch() throws Exception { + TestRunner runner = new TestRunner(); + this.dispatcher.dispatch(runner); + Thread.sleep(1000); + Assert.assertTrue(runner.ran); - } - } + } + @Test(expected = NullPointerException.class) + public void testDispatchNull() throws Exception { + this.dispatcher.dispatch(null); + } - @Test - public void testDispatcherStop() throws Exception { + @Test + public void testDispatcherStop() throws Exception { this.dispatcher.stop(); - TestRunner runner = new TestRunner(); - this.dispatcher.dispatch(runner); - Thread.sleep(1000); - Assert.assertFalse(runner.ran); - } - - - @Test - public void testDispatchReject() throws Exception { - this.dispatcher.stop(); - PoolDispatcher.MAX_POOL_SIZE_FACTOR = 1; - PoolDispatcher.POOL_QUEUE_SIZE_FACTOR = 1; - this.dispatcher = new PoolDispatcher(1, 60, TimeUnit.SECONDS, new ThreadPoolExecutor.AbortPolicy(),"test"); - this.dispatcher.dispatch(new Runnable() { - public void run() { - while (!Thread.currentThread().isInterrupted()) { - - } - } - }); - this.dispatcher.dispatch(new Runnable() { - public void run() { - while (!Thread.currentThread().isInterrupted()) { - - } - } - }); - - try { - this.dispatcher.dispatch(new TestRunner()); - Assert.fail(); - } - catch (RejectedExecutionException e) { - - } - PoolDispatcher.MAX_POOL_SIZE_FACTOR = 1.25f; - PoolDispatcher.POOL_QUEUE_SIZE_FACTOR = 1000; - } - - - @After - public void tearDown() { - this.dispatcher.stop(); - - } - + TestRunner runner = new TestRunner(); + this.dispatcher.dispatch(runner); + Thread.sleep(1000); + Assert.assertFalse(runner.ran); + } + + @Test(expected = RejectedExecutionException.class) + public void testDispatchReject() throws Exception { + this.dispatcher = new PoolDispatcher(1, 1, 1, 60, TimeUnit.SECONDS, new ThreadPoolExecutor.AbortPolicy(), + "test"); + this.dispatcher.dispatch(new Runnable() { + public void run() { + while (!Thread.currentThread().isInterrupted()) { + + } + } + }); + this.dispatcher.dispatch(new Runnable() { + public void run() { + while (!Thread.currentThread().isInterrupted()) { + + } + } + }); + + // Should throw a RejectedExecutionException + this.dispatcher.dispatch(new TestRunner()); + } } From 40b76fa111a497307aa361843f728bd84ab6171c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Mon, 1 Feb 2016 14:46:45 -0800 Subject: [PATCH 038/207] jta dependency should have a scope of provided to match hibernate-memcached scope --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index f1b02c2c4..473365fe5 100644 --- a/pom.xml +++ b/pom.xml @@ -186,6 +186,7 @@ javax.transaction jta ${jta.version} + provided From 2a26474d64e27fe9ffb6af468cf971f6392a514a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Mon, 1 Feb 2016 18:14:56 -0800 Subject: [PATCH 039/207] This change does the following: * Update JUnit to the latest version * Split tests in unit tests and integration tests. At some point we may want to separate them in different directories * Run unit tests in parallel. Ex: Time to run unit tests went from 50s to 14s on my box --- pom.xml | 53 ++++++++++++++++++- ...Test.java => BinaryMemcachedClientIT.java} | 2 +- ...a => ConnectionPoolMemcachedClientIT.java} | 2 +- ...a => ConsistentHashMemcachedClientIT.java} | 2 +- ...ientUnitTest.java => KestrelClientIT.java} | 6 +-- ...ava => StandardHashMemcachedClientIT.java} | 2 +- ...lientTest.java => XMemcachedClientIT.java} | 2 +- ...=> XMemcachedClientWithKeyProviderIT.java} | 2 +- ...java => XmemcacheClientFactoryUnitIT.java} | 2 +- ...va => MemcachedClientStateListenerIT.java} | 2 +- ...ava => XMemcachedClientFactoryBeanIT.java} | 2 +- 11 files changed, 63 insertions(+), 14 deletions(-) rename src/test/java/net/rubyeye/xmemcached/test/unittest/{BinaryMemcachedClientUnitTest.java => BinaryMemcachedClientIT.java} (95%) rename src/test/java/net/rubyeye/xmemcached/test/unittest/{ConnectionPoolMemcachedClientTest.java => ConnectionPoolMemcachedClientIT.java} (95%) rename src/test/java/net/rubyeye/xmemcached/test/unittest/{ConsistentHashMemcachedClientTest.java => ConsistentHashMemcachedClientIT.java} (90%) rename src/test/java/net/rubyeye/xmemcached/test/unittest/{KestrelClientUnitTest.java => KestrelClientIT.java} (94%) rename src/test/java/net/rubyeye/xmemcached/test/unittest/{StandardHashMemcachedClientTest.java => StandardHashMemcachedClientIT.java} (95%) rename src/test/java/net/rubyeye/xmemcached/test/unittest/{XMemcachedClientTest.java => XMemcachedClientIT.java} (96%) rename src/test/java/net/rubyeye/xmemcached/test/unittest/{XMemcachedClientWithKeyProviderTest.java => XMemcachedClientWithKeyProviderIT.java} (93%) rename src/test/java/net/rubyeye/xmemcached/test/unittest/hibernate/{XmemcacheClientFactoryUnitTest.java => XmemcacheClientFactoryUnitIT.java} (94%) rename src/test/java/net/rubyeye/xmemcached/test/unittest/impl/{MemcachedClientStateListenerUnitTest.java => MemcachedClientStateListenerIT.java} (94%) rename src/test/java/net/rubyeye/xmemcached/test/unittest/utils/{XMemcachedClientFactoryBeanUnitTest.java => XMemcachedClientFactoryBeanIT.java} (93%) diff --git a/pom.xml b/pom.xml index 473365fe5..53bb81d63 100644 --- a/pom.xml +++ b/pom.xml @@ -58,13 +58,20 @@ bmahe + + ${cpu.count} + false + 1.5 1.5 UTF-8 + 1.10 2.6 2.10 2.10 + 2.19.1 3.0.1 2.1 3.0.1 @@ -80,7 +87,7 @@ 1.2 1.1 1.2.16 - 4.4 + 4.12 2.4 localhost @@ -109,6 +116,22 @@ + + org.codehaus.mojo + build-helper-maven-plugin + ${build.helper.maven.plugin.version} + + + get-cpu-count + + cpu-count + + + cpu.count + + + + org.apache.maven.plugins maven-javadoc-plugin @@ -138,11 +161,29 @@ org.apache.maven.plugins maven-surefire-plugin ${maven.surefire.plugin.version} + + true + classes + ${surefire.perCoreThreadCount} + ${surefire.thread.count} + + + + org.apache.maven.plugins + maven-failsafe-plugin + ${maven.failsafe.plugin.version} + + + + integration-test + verify + + + true - org.apache.maven.plugins maven-assembly-plugin @@ -242,6 +283,14 @@ false + + + + failsafe-report-only + report-only + + + diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/BinaryMemcachedClientUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/BinaryMemcachedClientIT.java similarity index 95% rename from src/test/java/net/rubyeye/xmemcached/test/unittest/BinaryMemcachedClientUnitTest.java rename to src/test/java/net/rubyeye/xmemcached/test/unittest/BinaryMemcachedClientIT.java index 23036550e..6fac06c68 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/BinaryMemcachedClientUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/BinaryMemcachedClientIT.java @@ -23,7 +23,7 @@ * @author boyan * */ -public class BinaryMemcachedClientUnitTest extends XMemcachedClientTest { +public class BinaryMemcachedClientIT extends XMemcachedClientIT { @Override public MemcachedClientBuilder createBuilder() throws Exception { diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/ConnectionPoolMemcachedClientTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/ConnectionPoolMemcachedClientIT.java similarity index 95% rename from src/test/java/net/rubyeye/xmemcached/test/unittest/ConnectionPoolMemcachedClientTest.java rename to src/test/java/net/rubyeye/xmemcached/test/unittest/ConnectionPoolMemcachedClientIT.java index a324e2fa7..ec795e006 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/ConnectionPoolMemcachedClientTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/ConnectionPoolMemcachedClientIT.java @@ -16,7 +16,7 @@ import com.google.code.yanf4j.core.impl.HandlerAdapter; import com.google.code.yanf4j.nio.TCPController; -public class ConnectionPoolMemcachedClientTest extends XMemcachedClientTest { +public class ConnectionPoolMemcachedClientIT extends XMemcachedClientIT { private static final int CONNECTION_POOL_SIZE = 3; @Override diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/ConsistentHashMemcachedClientTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/ConsistentHashMemcachedClientIT.java similarity index 90% rename from src/test/java/net/rubyeye/xmemcached/test/unittest/ConsistentHashMemcachedClientTest.java rename to src/test/java/net/rubyeye/xmemcached/test/unittest/ConsistentHashMemcachedClientIT.java index af63c89bd..adbef2830 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/ConsistentHashMemcachedClientTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/ConsistentHashMemcachedClientIT.java @@ -8,7 +8,7 @@ import net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator; import net.rubyeye.xmemcached.utils.AddrUtil; -public class ConsistentHashMemcachedClientTest extends StandardHashMemcachedClientTest { +public class ConsistentHashMemcachedClientIT extends StandardHashMemcachedClientIT { @Override public MemcachedClientBuilder createBuilder() throws Exception { MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/KestrelClientUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/KestrelClientIT.java similarity index 94% rename from src/test/java/net/rubyeye/xmemcached/test/unittest/KestrelClientUnitTest.java rename to src/test/java/net/rubyeye/xmemcached/test/unittest/KestrelClientIT.java index a88002d16..cdfe5b134 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/KestrelClientUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/KestrelClientIT.java @@ -19,7 +19,7 @@ import com.google.code.yanf4j.util.ResourcesUtils; -public class KestrelClientUnitTest extends TestCase { +public class KestrelClientIT extends TestCase { static class UserDefinedClass implements Serializable { private String name; @@ -231,11 +231,11 @@ public void run() { try { this.cyclicBarrier.await(); for (int i = 0; i < 10000; i++) { - KestrelClientUnitTest.this.memcachedClient.set("queue1", 0, + KestrelClientIT.this.memcachedClient.set("queue1", 0, "hello"); } for (int i = 0; i < 10000; i++) { - KestrelClientUnitTest.this.memcachedClient.get("queue1"); + KestrelClientIT.this.memcachedClient.get("queue1"); } this.cyclicBarrier.await(); } catch (Exception e) { diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/StandardHashMemcachedClientTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/StandardHashMemcachedClientIT.java similarity index 95% rename from src/test/java/net/rubyeye/xmemcached/test/unittest/StandardHashMemcachedClientTest.java rename to src/test/java/net/rubyeye/xmemcached/test/unittest/StandardHashMemcachedClientIT.java index 791cfb04a..2a0d05a04 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/StandardHashMemcachedClientTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/StandardHashMemcachedClientIT.java @@ -13,7 +13,7 @@ import net.rubyeye.xmemcached.transcoders.StringTranscoder; import net.rubyeye.xmemcached.utils.AddrUtil; -public class StandardHashMemcachedClientTest extends XMemcachedClientTest { +public class StandardHashMemcachedClientIT extends XMemcachedClientIT { @Override public MemcachedClientBuilder createBuilder() throws Exception { diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientIT.java similarity index 96% rename from src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientTest.java rename to src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientIT.java index 7a6459ba1..aa1f418f2 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientIT.java @@ -54,7 +54,7 @@ import com.google.code.yanf4j.buffer.IoBuffer; import com.google.code.yanf4j.util.ResourcesUtils; -public abstract class XMemcachedClientTest extends TestCase { +public abstract class XMemcachedClientIT extends TestCase { protected MemcachedClient memcachedClient; Properties properties; private MockTranscoder mockTranscoder; diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientWithKeyProviderTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientWithKeyProviderIT.java similarity index 93% rename from src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientWithKeyProviderTest.java rename to src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientWithKeyProviderIT.java index 2d7d42fc5..65d8e01e3 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientWithKeyProviderTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientWithKeyProviderIT.java @@ -12,7 +12,7 @@ import net.rubyeye.xmemcached.utils.AddrUtil; import net.rubyeye.xmemcached.utils.ByteUtils; -public class XMemcachedClientWithKeyProviderTest extends XMemcachedClientTest{ +public class XMemcachedClientWithKeyProviderIT extends XMemcachedClientIT{ private KeyProvider keyProvider; diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/hibernate/XmemcacheClientFactoryUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/hibernate/XmemcacheClientFactoryUnitIT.java similarity index 94% rename from src/test/java/net/rubyeye/xmemcached/test/unittest/hibernate/XmemcacheClientFactoryUnitTest.java rename to src/test/java/net/rubyeye/xmemcached/test/unittest/hibernate/XmemcacheClientFactoryUnitIT.java index ca9a2e746..f7cdc1e26 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/hibernate/XmemcacheClientFactoryUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/hibernate/XmemcacheClientFactoryUnitIT.java @@ -11,7 +11,7 @@ import com.googlecode.hibernate.memcached.PropertiesHelper; import com.googlecode.hibernate.memcached.spymemcached.SpyMemcacheClientFactory; -public class XmemcacheClientFactoryUnitTest extends TestCase { +public class XmemcacheClientFactoryUnitIT extends TestCase { Properties properties; @Override diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/MemcachedClientStateListenerUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/MemcachedClientStateListenerIT.java similarity index 94% rename from src/test/java/net/rubyeye/xmemcached/test/unittest/impl/MemcachedClientStateListenerUnitTest.java rename to src/test/java/net/rubyeye/xmemcached/test/unittest/impl/MemcachedClientStateListenerIT.java index 31061c788..0629eddda 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/MemcachedClientStateListenerUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/MemcachedClientStateListenerIT.java @@ -12,7 +12,7 @@ import net.rubyeye.xmemcached.utils.AddrUtil; import junit.framework.TestCase; -public class MemcachedClientStateListenerUnitTest extends TestCase { +public class MemcachedClientStateListenerIT extends TestCase { MemcachedClient memcachedClient; MockMemcachedClientStateListener listener; diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/utils/XMemcachedClientFactoryBeanUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/utils/XMemcachedClientFactoryBeanIT.java similarity index 93% rename from src/test/java/net/rubyeye/xmemcached/test/unittest/utils/XMemcachedClientFactoryBeanUnitTest.java rename to src/test/java/net/rubyeye/xmemcached/test/unittest/utils/XMemcachedClientFactoryBeanIT.java index 3d33fc8ee..690a2ffd7 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/utils/XMemcachedClientFactoryBeanUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/utils/XMemcachedClientFactoryBeanIT.java @@ -10,7 +10,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; -public class XMemcachedClientFactoryBeanUnitTest extends TestCase { +public class XMemcachedClientFactoryBeanIT extends TestCase { ApplicationContext ctx; From 01632c6b7fb0681ce8b7303787bd99ef0dc057a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Mon, 1 Feb 2016 18:23:12 -0800 Subject: [PATCH 040/207] Fix TextLineCodecFactoryUnitTest::decodeNormal See http://bmahe.github.io/xmemcached/surefire-report.html#com.google.code.yanf4j.test.unittest.core.impl.TextLineCodecFactoryUnitTest.decodeNormal --- .../impl/TextLineCodecFactoryUnitTest.java | 87 +++++++++---------- 1 file changed, 41 insertions(+), 46 deletions(-) diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/TextLineCodecFactoryUnitTest.java b/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/TextLineCodecFactoryUnitTest.java index 782ab44f0..84ca883cf 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/TextLineCodecFactoryUnitTest.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/TextLineCodecFactoryUnitTest.java @@ -8,7 +8,6 @@ import com.google.code.yanf4j.core.CodecFactory.Encoder; import com.google.code.yanf4j.core.impl.TextLineCodecFactory; - /** * * @@ -19,50 +18,46 @@ */ public class TextLineCodecFactoryUnitTest { - TextLineCodecFactory textLineCodecFactory; - - - @Before - public void setUp() { - this.textLineCodecFactory = new TextLineCodecFactory(); - } - - - @Test - public void testEncodeNormal() throws Exception { - Encoder encoder = this.textLineCodecFactory.getEncoder(); - Assert.assertNotNull(encoder); - IoBuffer buffer = encoder.encode("hello", null); - Assert.assertNotNull(buffer); - Assert.assertTrue(buffer.hasRemaining()); - Assert.assertArrayEquals("hello\r\n".getBytes("utf-8"), buffer.array()); - - } - - - @Test - public void testEncodeEmpty() throws Exception { - Encoder encoder = this.textLineCodecFactory.getEncoder(); - Assert.assertNull(encoder.encode(null, null)); - Assert.assertEquals(TextLineCodecFactory.SPLIT, encoder.encode("", null)); - } - - - @Test - public void decodeNormal() throws Exception { - Encoder encoder = this.textLineCodecFactory.getEncoder(); - Assert.assertNotNull(encoder); - IoBuffer buffer = encoder.encode("hello", null); - - String str = (String) this.textLineCodecFactory.getDecoder().decode(buffer, null); - Assert.assertEquals("hello", str); - } - - - @Test - public void decodeEmpty() throws Exception { - Assert.assertNull(this.textLineCodecFactory.getDecoder().decode(null, null)); - Assert.assertEquals("", this.textLineCodecFactory.getDecoder().decode(TextLineCodecFactory.SPLIT, null)); - } + TextLineCodecFactory textLineCodecFactory; + + @Before + public void setUp() { + this.textLineCodecFactory = new TextLineCodecFactory(); + TextLineCodecFactory.SPLIT.clear(); + } + + @Test + public void testEncodeNormal() throws Exception { + Encoder encoder = this.textLineCodecFactory.getEncoder(); + Assert.assertNotNull(encoder); + IoBuffer buffer = encoder.encode("hello", null); + Assert.assertNotNull(buffer); + Assert.assertTrue(buffer.hasRemaining()); + Assert.assertArrayEquals("hello\r\n".getBytes("utf-8"), buffer.array()); + + } + + @Test + public void testEncodeEmpty() throws Exception { + Encoder encoder = this.textLineCodecFactory.getEncoder(); + Assert.assertNull(encoder.encode(null, null)); + Assert.assertEquals(TextLineCodecFactory.SPLIT, encoder.encode("", null)); + } + + @Test + public void decodeNormal() throws Exception { + Encoder encoder = this.textLineCodecFactory.getEncoder(); + Assert.assertNotNull(encoder); + IoBuffer buffer = encoder.encode("hello", null); + + String str = (String) this.textLineCodecFactory.getDecoder().decode(buffer, null); + Assert.assertEquals("hello", str); + } + + @Test + public void decodeEmpty() throws Exception { + Assert.assertNull(this.textLineCodecFactory.getDecoder().decode(null, null)); + Assert.assertEquals("", this.textLineCodecFactory.getDecoder().decode(TextLineCodecFactory.SPLIT, null)); + } } From 74c8bada13db1af8c8ff2269c34a274a37b1f7b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Mon, 1 Feb 2016 19:00:27 -0800 Subject: [PATCH 041/207] Downgrade build helper plugin so the project can be built on an older jvm --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 53bb81d63..67ba0e8d7 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,7 @@ 1.5 UTF-8 - 1.10 + 1.9.1 2.6 2.10 2.10 From f36cc034d0d80eda287dfbf52df4322271811ba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Mon, 1 Feb 2016 19:49:10 -0800 Subject: [PATCH 042/207] Fix XMemcachedClientWithKeyProviderIT::testWeightedServers by implementing a missing factory method --- .../XMemcachedClientWithKeyProviderIT.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientWithKeyProviderIT.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientWithKeyProviderIT.java index 65d8e01e3..8c5161cc1 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientWithKeyProviderIT.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientWithKeyProviderIT.java @@ -1,5 +1,7 @@ package net.rubyeye.xmemcached.test.unittest; +import java.net.InetSocketAddress; +import java.util.List; import java.util.concurrent.TimeoutException; import net.rubyeye.xmemcached.KeyProvider; @@ -9,6 +11,7 @@ import net.rubyeye.xmemcached.XMemcachedClientBuilder; import net.rubyeye.xmemcached.command.BinaryCommandFactory; import net.rubyeye.xmemcached.exception.MemcachedException; +import net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator; import net.rubyeye.xmemcached.utils.AddrUtil; import net.rubyeye.xmemcached.utils.ByteUtils; @@ -39,6 +42,24 @@ public MemcachedClientBuilder createBuilder() throws Exception { return builder; } + @Override + public MemcachedClientBuilder createWeightedBuilder() throws Exception { + List addressList = AddrUtil + .getAddresses(this.properties + .getProperty("test.memcached.servers")); + int[] weights = new int[addressList.size()]; + for (int i = 0; i < weights.length; i++) { + weights[i] = i + 1; + } + + MemcachedClientBuilder builder = new XMemcachedClientBuilder( + addressList, weights); + builder.setCommandFactory(new BinaryCommandFactory()); + ByteUtils.testing = true; + return builder; + } + + public void testKeyProvider(){ String process = keyProvider.process("namespace:a"); assertEquals("790852098", process); From 973337232f7aa3dfb394090b21900f6ceca52d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Tue, 2 Feb 2016 12:27:53 -0800 Subject: [PATCH 043/207] Run integration tests as part of the travis build --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 5ceb503d2..90da0d9e7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,8 @@ jdk: - openjdk6 services: - memcached +script: + - mvn verify after_script: - '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && travis_wait 300 mvn site -Ppublish-site-github || false' env: From f75578ee79348816a99f73bf36a4ea8886d0df43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Mah=C3=A9?= Date: Mon, 8 Feb 2016 19:05:18 -0800 Subject: [PATCH 044/207] Fix XMemcachedClientFactoryBeanIT by specifying Spring config to use a list of Integer for the weights. Otherwise they get injected as a list of String and create a class cast exception --- src/test/resources/applicationContext.xml | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/test/resources/applicationContext.xml b/src/test/resources/applicationContext.xml index 292c1b944..360c697c1 100644 --- a/src/test/resources/applicationContext.xml +++ b/src/test/resources/applicationContext.xml @@ -1,9 +1,11 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd + http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd"> + class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" + destroy-method="shutdown"> classpath:test.properties @@ -12,26 +14,27 @@ class="net.rubyeye.xmemcached.utils.XMemcachedClientFactoryBean"> ${test.memcached.servers} - + + class="net.rubyeye.xmemcached.utils.XMemcachedClientFactoryBean" + destroy-method="shutdown"> ${test.memcached.servers} - + 1 2 3 4 5 - + - + From 81b350fe29baa5f45efe4117f0b0742556f5e2c2 Mon Sep 17 00:00:00 2001 From: SnailKnows Date: Fri, 15 Apr 2016 19:31:56 +0800 Subject: [PATCH 045/207] Update XMemcachedClient.java Check Null --- src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java index 9353a5bba..cca23cc82 100644 --- a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java +++ b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java @@ -542,9 +542,9 @@ public final void removeServer(String hostList) { .getStandbySessionListByMainNodeAddr(address); if (standBySession != null) { for (Session session : standBySession) { - this.connector.removeReconnectRequest(session - .getRemoteSocketAddress()); if (session != null) { + this.connector.removeReconnectRequest(session + .getRemoteSocketAddress()); // Disable auto reconnection ((MemcachedSession) session) .setAllowReconnect(false); From 975aeda1f990e178f6364fa92bb045f0b3576251 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Fri, 17 Jun 2016 11:47:29 +0800 Subject: [PATCH 046/207] (fix) Fixed XMemcachedClientWithKeyProviderIT --- pom.xml | 9 +--- .../XMemcachedClientWithKeyProviderIT.java | 49 ++++++++++--------- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/pom.xml b/pom.xml index 67ba0e8d7..45e13b746 100644 --- a/pom.xml +++ b/pom.xml @@ -48,17 +48,12 @@ false - - hibernate-memcached - hibernate-memcached - http://raykrueger.googlecode.com/svn/repository - bmahe - ${cpu.count} false @@ -221,7 +216,7 @@ - javax.transaction diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientWithKeyProviderIT.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientWithKeyProviderIT.java index 8c5161cc1..3f3f937cf 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientWithKeyProviderIT.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientWithKeyProviderIT.java @@ -15,33 +15,33 @@ import net.rubyeye.xmemcached.utils.AddrUtil; import net.rubyeye.xmemcached.utils.ByteUtils; -public class XMemcachedClientWithKeyProviderIT extends XMemcachedClientIT{ - +public class XMemcachedClientWithKeyProviderIT extends XMemcachedClientIT { + private KeyProvider keyProvider; - + @Override public void setUp() throws Exception { super.setUp(); keyProvider = new KeyProvider() { - + public String process(String key) { // 现实中是基于某种规则进行字符串转换, 为了简单, 我直接用hashCode return String.valueOf(key.hashCode()); } }; } - + @Override public MemcachedClientBuilder createBuilder() throws Exception { - MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil - .getAddresses(this.properties + MemcachedClientBuilder builder = new XMemcachedClientBuilder( + AddrUtil.getAddresses(this.properties .getProperty("test.memcached.servers"))); builder.setCommandFactory(new BinaryCommandFactory()); ByteUtils.testing = true; return builder; } - + @Override public MemcachedClientBuilder createWeightedBuilder() throws Exception { List addressList = AddrUtil @@ -54,36 +54,39 @@ public MemcachedClientBuilder createWeightedBuilder() throws Exception { MemcachedClientBuilder builder = new XMemcachedClientBuilder( addressList, weights); - builder.setCommandFactory(new BinaryCommandFactory()); + builder.setSessionLocator(new KetamaMemcachedSessionLocator()); ByteUtils.testing = true; return builder; } - - public void testKeyProvider(){ + public void testKeyProvider() { String process = keyProvider.process("namespace:a"); assertEquals("790852098", process); } - - public void testWithNamespaceAndKeyProvider() throws Exception{ + + public void testWithNamespaceAndKeyProvider() throws Exception { memcachedClient.setKeyProvider(keyProvider); memcachedClient.withNamespace("a", new MemcachedClientCallable() { - public Void call(MemcachedClient client) throws MemcachedException, InterruptedException, TimeoutException { + public Void call(MemcachedClient client) throws MemcachedException, + InterruptedException, TimeoutException { client.set("name", 0, "Mike Liu"); return null; } }); - + memcachedClient.invalidateNamespace("a"); - - Object result = memcachedClient.withNamespace("a", new MemcachedClientCallable() { - public Object call(MemcachedClient client) throws MemcachedException, InterruptedException, TimeoutException { - return memcachedClient.get("name"); - } - }); - + + Object result = memcachedClient.withNamespace("a", + new MemcachedClientCallable() { + public Object call(MemcachedClient client) + throws MemcachedException, InterruptedException, + TimeoutException { + return memcachedClient.get("name"); + } + }); + assertNull(result); } - + } From 7fede112b94fd5372b3026dcd4f296dbf5be8923 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Fri, 17 Jun 2016 11:55:14 +0800 Subject: [PATCH 047/207] (feat) Update Build Status --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 72ab7cb44..268049734 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://travis-ci.org/bmahe/xmemcached.svg?branch=tango)](https://travis-ci.org/bmahe/xmemcached) +[![Build Status](https://travis-ci.org/killme2008/xmemcached.svg?branch=tango)](https://travis-ci.org/killme2008/xmemcached) ##Introduction From 8abcadd99bdbe3dca9fd25ebaa98812fadf58a3f Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Fri, 17 Jun 2016 12:02:12 +0800 Subject: [PATCH 048/207] Revert XMemcachedClientWithKeyProviderIT --- .../test/unittest/XMemcachedClientWithKeyProviderIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientWithKeyProviderIT.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientWithKeyProviderIT.java index 3f3f937cf..38752855f 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientWithKeyProviderIT.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientWithKeyProviderIT.java @@ -54,7 +54,7 @@ public MemcachedClientBuilder createWeightedBuilder() throws Exception { MemcachedClientBuilder builder = new XMemcachedClientBuilder( addressList, weights); - builder.setSessionLocator(new KetamaMemcachedSessionLocator()); + builder.setCommandFactory(new BinaryCommandFactory()); ByteUtils.testing = true; return builder; } From 9edff1b2fe9bda40160c23c3f6115af149d9b373 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Fri, 17 Jun 2016 12:08:52 +0800 Subject: [PATCH 049/207] (fix) Fixed testTouch in XMemcachedClientWithKeyProviderIT --- .../test/unittest/XMemcachedClientWithKeyProviderIT.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientWithKeyProviderIT.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientWithKeyProviderIT.java index 38752855f..8075d68ce 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientWithKeyProviderIT.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientWithKeyProviderIT.java @@ -9,9 +9,7 @@ import net.rubyeye.xmemcached.MemcachedClientBuilder; import net.rubyeye.xmemcached.MemcachedClientCallable; import net.rubyeye.xmemcached.XMemcachedClientBuilder; -import net.rubyeye.xmemcached.command.BinaryCommandFactory; import net.rubyeye.xmemcached.exception.MemcachedException; -import net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator; import net.rubyeye.xmemcached.utils.AddrUtil; import net.rubyeye.xmemcached.utils.ByteUtils; @@ -25,8 +23,7 @@ public void setUp() throws Exception { keyProvider = new KeyProvider() { public String process(String key) { - // 现实中是基于某种规则进行字符串转换, 为了简单, 我直接用hashCode - return String.valueOf(key.hashCode()); + return "prefix-" + key; } }; } @@ -37,7 +34,6 @@ public MemcachedClientBuilder createBuilder() throws Exception { MemcachedClientBuilder builder = new XMemcachedClientBuilder( AddrUtil.getAddresses(this.properties .getProperty("test.memcached.servers"))); - builder.setCommandFactory(new BinaryCommandFactory()); ByteUtils.testing = true; return builder; } @@ -54,14 +50,13 @@ public MemcachedClientBuilder createWeightedBuilder() throws Exception { MemcachedClientBuilder builder = new XMemcachedClientBuilder( addressList, weights); - builder.setCommandFactory(new BinaryCommandFactory()); ByteUtils.testing = true; return builder; } public void testKeyProvider() { String process = keyProvider.process("namespace:a"); - assertEquals("790852098", process); + assertEquals("prefix-namespace:a", process); } public void testWithNamespaceAndKeyProvider() throws Exception { From 7687994e5d4e054314bd120f85f2936841ce55ca Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Fri, 17 Jun 2016 12:09:51 +0800 Subject: [PATCH 050/207] (fix) Fixed readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 268049734..d954506c8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://travis-ci.org/killme2008/xmemcached.svg?branch=tango)](https://travis-ci.org/killme2008/xmemcached) +[![Build Status](https://travis-ci.org/killme2008/xmemcached.svg?branch=master)](https://travis-ci.org/killme2008/xmemcached) ##Introduction From dbb5e97ebc409b826209683eb80f7d318ee0a6ca Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Wed, 27 Jul 2016 12:17:18 +0800 Subject: [PATCH 051/207] (feat) Adds system env: xmemcached.shutdown.hook.enable to control shutdown hook, close #44 --- .../rubyeye/xmemcached/XMemcachedClient.java | 45 ++++++++++++------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java index cca23cc82..4893cdeff 100644 --- a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java +++ b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java @@ -110,6 +110,17 @@ public class XMemcachedClient implements XMemcachedClientMBean, MemcachedClient private final CopyOnWriteArrayList stateListenerAdapters = new CopyOnWriteArrayList(); private Thread shutdownHookThread; + + /** + * System property to control shutdown hook, issue #44 + * + * @since 2.0.1 + */ + private boolean isEnableShutDownHook() { + return Boolean.valueOf(System.getProperty( + "xmemcached.shutdown.hook.enable", "true")); + } + private volatile boolean isHutdownHookCalled = false; // key provider for pre-processing keys before sending them to memcached // added by dennis,2012-07-14 @@ -670,18 +681,20 @@ private final void startConnector() throws IOException { this.shutdown = false; this.connector.start(); this.memcachedHandler.start(); - this.shutdownHookThread = new Thread() { - @Override - public void run() { - try { - XMemcachedClient.this.isHutdownHookCalled = true; - XMemcachedClient.this.shutdown(); - } catch (IOException e) { - log.error("Shutdown XMemcachedClient error", e); + if (isEnableShutDownHook()) { + this.shutdownHookThread = new Thread() { + @Override + public void run() { + try { + XMemcachedClient.this.isHutdownHookCalled = true; + XMemcachedClient.this.shutdown(); + } catch (IOException e) { + log.error("Shutdown XMemcachedClient error", e); + } } - } - }; - Runtime.getRuntime().addShutdownHook(this.shutdownHookThread); + }; + Runtime.getRuntime().addShutdownHook(this.shutdownHookThread); + } } } @@ -1251,7 +1264,7 @@ private final Map getMulti0(final Collection keys, @SuppressWarnings("unchecked") private Map reduceResult(final CommandType cmdType, final Transcoder transcoder, final List commands) - throws MemcachedException,InterruptedException,TimeoutException { + throws MemcachedException, InterruptedException, TimeoutException { final Map result = new HashMap(commands.size()); for (Command getCmd : commands) { getCmd.getIoBuffer().free(); @@ -1717,8 +1730,8 @@ private final boolean cas0(final String key, final int exp, tryCount++; result = this.gets0(key, keyBytes, transcoder); if (result == null) { - throw new NoValueException( - "could not gets the value for Key=" + key + " for cas"); + throw new NoValueException("could not gets the value for Key=" + + key + " for cas"); } if (tryCount > operation.getMaxTries()) { throw new TimeoutException("CAS try times is greater than max"); @@ -2396,7 +2409,7 @@ public final void shutdown() throws IOException { this.connector.stop(); this.memcachedHandler.stop(); XMemcachedMbeanServer.getInstance().shutdown(); - if (!this.isHutdownHookCalled) { + if (isEnableShutDownHook() && !this.isHutdownHookCalled) { try { Runtime.getRuntime() .removeShutdownHook(this.shutdownHookThread); @@ -2636,7 +2649,7 @@ private String decodeKey(String key) throws MemcachedException, String nsValue = this.getNamespace(ns); try { if (nsValue != null && key.startsWith(nsValue)) { - //The extra length of ':' + // The extra length of ':' key = key.substring(nsValue.length() + 1); } else { return null; From 449e5c928b46c39354b4a2944d3c3162db071f63 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Wed, 27 Jul 2016 12:29:22 +0800 Subject: [PATCH 052/207] (feat) Make log more friendly, close #25 --- .../code/yanf4j/core/impl/AbstractController.java | 2 +- .../java/net/rubyeye/xmemcached/XMemcachedClient.java | 4 ++-- .../rubyeye/xmemcached/impl/MemcachedConnector.java | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/google/code/yanf4j/core/impl/AbstractController.java b/src/main/java/com/google/code/yanf4j/core/impl/AbstractController.java index 76b0a5815..b24ad7d08 100644 --- a/src/main/java/com/google/code/yanf4j/core/impl/AbstractController.java +++ b/src/main/java/com/google/code/yanf4j/core/impl/AbstractController.java @@ -370,7 +370,7 @@ public void run() { } }; Runtime.getRuntime().addShutdownHook(shutdownHookThread); - log.warn("The Controller started at " + localSocketAddress + " ..."); + log.info("The Controller started at " + localSocketAddress + " ..."); } protected abstract void start0() throws IOException; diff --git a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java index 4893cdeff..175213837 100644 --- a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java +++ b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java @@ -738,7 +738,7 @@ private void buildConnector(MemcachedSessionLocator locator, } this.commandFactory = commandFactory; ByteUtils.setProtocol(this.commandFactory.getProtocol()); - log.warn("XMemcachedClient is using " + log.info("XMemcachedClient is using " + this.commandFactory.getProtocol().name() + " protocol"); this.commandFactory.setBufferAllocator(bufferAllocator); this.shutdown = true; @@ -753,7 +753,7 @@ private void buildConnector(MemcachedSessionLocator locator, this.connector.setSessionTimeout(-1); this.connector.setSocketOptions(socketOptions); if (this.isFailureMode()) { - log.warn("XMemcachedClient in failure mode."); + log.info("XMemcachedClient in failure mode."); } this.connector.setFailureMode(this.failureMode); this.sessionLocator.setFailureMode(this.failureMode); diff --git a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java index e1331a5ae..d238706d4 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java @@ -119,7 +119,7 @@ public void run() { .connect(request.getInetSocketAddressWrapper()); request.setTries(request.getTries() + 1); try { - log.warn("Trying to connect to " + log.info("Trying to connect to " + address.getAddress().getHostAddress() + ":" + address.getPort() + " for " + request.getTries() + " times"); @@ -142,7 +142,7 @@ public void run() { } } } else { - log.warn("Remove invalid reconnect task for " + address); + log.info("Remove invalid reconnect task for " + address); // remove reconnect task } } catch (InterruptedException e) { @@ -245,7 +245,7 @@ public synchronized void addSession(Session session) { private void addMainSession(Session session) { InetSocketAddress remoteSocketAddress = session .getRemoteSocketAddress(); - log.warn("Add a session: " + log.info("Add a session: " + SystemUtils.getRawAddress(remoteSocketAddress) + ":" + remoteSocketAddress.getPort()); Queue sessions = this.sessionMap.get(remoteSocketAddress); @@ -282,7 +282,7 @@ private void addStandbySession(Session session, InetSocketAddress mainNodeAddress) { InetSocketAddress remoteSocketAddress = session .getRemoteSocketAddress(); - log.warn("Add a standby session: " + log.info("Add a standby session: " + SystemUtils.getRawAddress(remoteSocketAddress) + ":" + remoteSocketAddress.getPort() + " for " + SystemUtils.getRawAddress(mainNodeAddress) + ":" @@ -359,7 +359,7 @@ private void removeMainSession(Session session) { + remoteSocketAddress.getPort()); return; } - log.warn("Remove a session: " + log.info("Remove a session: " + SystemUtils.getRawAddress(remoteSocketAddress) + ":" + remoteSocketAddress.getPort()); Queue sessionQueue = this.sessionMap.get(session From f731ccb73bd4d01f9cc05ddaec27047d5e4df94e Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Wed, 27 Jul 2016 20:09:09 +0800 Subject: [PATCH 053/207] (feat) Improve auth task for binary protocol. --- .../net/rubyeye/xmemcached/auth/AuthTask.java | 101 ++++++++++-------- 1 file changed, 56 insertions(+), 45 deletions(-) diff --git a/src/main/java/net/rubyeye/xmemcached/auth/AuthTask.java b/src/main/java/net/rubyeye/xmemcached/auth/AuthTask.java index dee27fab5..08da1a357 100644 --- a/src/main/java/net/rubyeye/xmemcached/auth/AuthTask.java +++ b/src/main/java/net/rubyeye/xmemcached/auth/AuthTask.java @@ -32,6 +32,7 @@ public class AuthTask extends Thread { private MemcachedTCPSession memcachedTCPSession; public static final byte[] EMPTY_BYTES = new byte[0]; static final Logger log = LoggerFactory.getLogger(AuthTask.class); + private SaslClient saslClient; public AuthTask(AuthInfo authInfo, CommandFactory commandFactory, MemcachedTCPSession memcachedTCPSession) { @@ -46,39 +47,17 @@ public void run() { doAuth(); this.authInfo.increaseAttempts(); } - } private void doAuth() { - SaslClient saslClient = null; try { - saslClient = Sasl.createSaslClient(authInfo.getMechanisms(), null, - "memcached", memcachedTCPSession.getRemoteSocketAddress() - .toString(), null, this.authInfo - .getCallbackHandler()); - final AtomicBoolean done = new AtomicBoolean(false); - byte[] response = saslClient.hasInitialResponse() ? saslClient - .evaluateChallenge(EMPTY_BYTES) : EMPTY_BYTES; - CountDownLatch latch = new CountDownLatch(1); - Command command = this.commandFactory.createAuthStartCommand( - saslClient.getMechanismName(), latch, response); - if (!this.memcachedTCPSession.isClosed()) - this.memcachedTCPSession.write(command); - else { - log - .error("Authentication fail,because the connection has been closed"); - throw new RuntimeException( - "Authentication fai,connection has been close"); - } + Command command = startAuth(); while (!done.get()) { - try { - latch.await(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - done.set(true); - } + // wait previous command response + waitCommand(command, done); + // process response ResponseStatus responseStatus = ((BaseBinaryCommand) command) .getResponseStatus(); switch (responseStatus) { @@ -89,16 +68,14 @@ private void doAuth() { + " successfully"); break; case AUTH_REQUIRED: - log - .error("Authentication failed to " - + this.memcachedTCPSession - .getRemoteSocketAddress()); + log.error("Authentication failed to " + + this.memcachedTCPSession.getRemoteSocketAddress()); log.warn("Reopen connection to " + this.memcachedTCPSession.getRemoteSocketAddress() + ",beacause auth fail"); this.memcachedTCPSession.setAuthFailed(true); - // It it is not first time,try to sleep 1 second + // It it is not first time ,try to sleep 1 second if (!this.authInfo.isFirstTime()) { Thread.sleep(1000); } @@ -106,28 +83,26 @@ private void doAuth() { done.set(true); break; case FUTHER_AUTH_REQUIRED: - System.out.println(command.getResult()); String result = String.valueOf(command.getResult()); - response = saslClient.evaluateChallenge(ByteUtils + byte[] response = saslClient.evaluateChallenge(ByteUtils .getBytes(result)); - latch = new CountDownLatch(1); - command = commandFactory.createAuthStepCommand(saslClient - .getMechanismName(), latch, response); + CountDownLatch latch = new CountDownLatch(1); + command = commandFactory.createAuthStepCommand( + saslClient.getMechanismName(), latch, response); if (!this.memcachedTCPSession.isClosed()) this.memcachedTCPSession.write(command); else { - log - .error("Authentication fail,because the connection has been closed"); + log.error("Authentication fail,because the connection has been closed"); throw new RuntimeException( "Authentication fai,connection has been close"); } break; default: - done.set(true); log.error("Authentication failed to " + this.memcachedTCPSession.getRemoteSocketAddress() + ",response status=" + responseStatus); + command = startAuth(); break; } @@ -136,13 +111,49 @@ private void doAuth() { } catch (Exception e) { log.error("Create saslClient error", e); } finally { - if (saslClient != null) { - try { - saslClient.dispose(); - } catch (SaslException e) { - log.error("Dispose saslClient error", e); - } + destroySaslClient(); + } + } + + private void destroySaslClient() { + if (saslClient != null) { + try { + saslClient.dispose(); + } catch (SaslException e) { + log.error("Dispose saslClient error", e); } + this.saslClient = null; + } + } + + private Command startAuth() throws SaslException { + // destroy previous client. + destroySaslClient(); + + this.saslClient = Sasl.createSaslClient(authInfo.getMechanisms(), null, + "memcached", memcachedTCPSession.getRemoteSocketAddress() + .toString(), null, this.authInfo.getCallbackHandler()); + byte[] response = saslClient.hasInitialResponse() ? saslClient + .evaluateChallenge(EMPTY_BYTES) : EMPTY_BYTES; + CountDownLatch latch = new CountDownLatch(1); + Command command = this.commandFactory.createAuthStartCommand( + saslClient.getMechanismName(), latch, response); + if (!this.memcachedTCPSession.isClosed()) + this.memcachedTCPSession.write(command); + else { + log.error("Authentication fail,because the connection has been closed"); + throw new RuntimeException( + "Authentication fai,connection has been close"); + } + return command; + } + + private void waitCommand(Command cmd, AtomicBoolean done) { + try { + cmd.getLatch().await(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + done.set(true); } } From f79780e5a3035d37fb9e995588d40a6c400d9234 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Wed, 27 Jul 2016 20:18:16 +0800 Subject: [PATCH 054/207] (fix) Don't run mvn verify in travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 90da0d9e7..ea2fb1e61 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ jdk: services: - memcached script: - - mvn verify + - mvn test after_script: - '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && travis_wait 300 mvn site -Ppublish-site-github || false' env: From 48657b5ffe2ad5fdfbd4ecc0b1333fd99030e920 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Wed, 27 Jul 2016 22:24:37 +0800 Subject: [PATCH 055/207] (feat) Disable shutdown hook by default --- src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java index 175213837..bc0d10e19 100644 --- a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java +++ b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java @@ -118,7 +118,7 @@ public class XMemcachedClient implements XMemcachedClientMBean, MemcachedClient */ private boolean isEnableShutDownHook() { return Boolean.valueOf(System.getProperty( - "xmemcached.shutdown.hook.enable", "true")); + "xmemcached.shutdown.hook.enable", "false")); } private volatile boolean isHutdownHookCalled = false; From 04ae3848cfbb84717d174f3cb74f3fecc626fafb Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Wed, 27 Jul 2016 22:34:13 +0800 Subject: [PATCH 056/207] (feat) Change some pom info --- pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 45e13b746..9af728113 100644 --- a/pom.xml +++ b/pom.xml @@ -13,13 +13,13 @@ 2.0.1-SNAPSHOT xmemcached Extreme performance modern memcached client for java - http://code.google.com/p/xmemcached/ + https://github.com/killme2008/xmemcached jar dennis zhuang - http://www.blogjava.net/killme2008/ + http://fnil.net/ 8 @@ -51,7 +51,7 @@ - bmahe + killme2008 @@ -70,7 +70,7 @@ 3.0.1 2.1 3.0.1 - 2.7 + 2.9 0.12 2.19.1 2.19.1 From f718ef8599a33fbcc8e4984bf6a9dd28e370f129 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Wed, 27 Jul 2016 22:44:12 +0800 Subject: [PATCH 057/207] (feat) Prepare to release 2.0.1 --- NOTICE.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/NOTICE.txt b/NOTICE.txt index bd2526a5e..f2c849567 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -5,6 +5,19 @@ Xmemcached Change log ******************************************* + +v2.0.1 + +1. Uses nano timestamp value as namespace. +2. Adds `setSelectorPoolSize` method to builder/client to set reactor pool size per client. +3. Set heartbeat thread and session monitor thread to be daemon. +4. Thanks to @bmahe, so much refactor and clean code. +5. Disable shutdown hook by default, you can change it by `-Dxmemcached.shutdown.hook.enable=true`. +6. Make log more friendly. +7. Fixed auth for binary protocol. +8. Some bug fix by contributors,thanks all of you. + + -----Xmemcached 2.0.0 release note ------------------ 1.Performance tweaks,10% improved for text protocol in my benchmark. From d81e0b11cd76f630bdbc17cf76e27bd2cc0b8bfd Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Wed, 27 Jul 2016 22:53:49 +0800 Subject: [PATCH 058/207] (fix) Fixed javadoc --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9af728113..f38acd9ff 100644 --- a/pom.xml +++ b/pom.xml @@ -380,7 +380,7 @@ [1.8,) - -Xdoclint:none + -Xdoclint:none From 0068fba5317caeae987b12b4f9e478fe4f775d1f Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Wed, 27 Jul 2016 22:59:04 +0800 Subject: [PATCH 059/207] (fix) Fixed javadoc --- pom.xml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index f38acd9ff..56eb592cd 100644 --- a/pom.xml +++ b/pom.xml @@ -1,6 +1,6 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> org.sonatype.oss oss-parent @@ -54,7 +54,7 @@ killme2008 + helper plugin --> ${cpu.count} false @@ -130,15 +130,16 @@ org.apache.maven.plugins maven-javadoc-plugin + 2.9.1 - attach-javadoc + attach-javadocs verify jar - ${javadoc.xdoclint} + ${javadoc.opts} @@ -217,7 +218,7 @@ + version is not available anymore --> javax.transaction jta From c4dd3e9bbfa1ded0795f50de4c9c3b03bb967d04 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Wed, 27 Jul 2016 23:07:02 +0800 Subject: [PATCH 060/207] [maven-release-plugin] prepare release xmemcached-2.0.1 --- pom.xml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 56eb592cd..53523055d 100644 --- a/pom.xml +++ b/pom.xml @@ -1,6 +1,5 @@ - + org.sonatype.oss oss-parent @@ -10,7 +9,7 @@ 4.0.0 com.googlecode.xmemcached xmemcached - 2.0.1-SNAPSHOT + 2.0.1 xmemcached Extreme performance modern memcached client for java https://github.com/killme2008/xmemcached From b5c4bd0abce545ce109465e843570732c9215f56 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Wed, 27 Jul 2016 23:07:15 +0800 Subject: [PATCH 061/207] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 53523055d..1edb40bee 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ 4.0.0 com.googlecode.xmemcached xmemcached - 2.0.1 + 2.0.2-SNAPSHOT xmemcached Extreme performance modern memcached client for java https://github.com/killme2008/xmemcached From 7a8a6d96a0bca01edc2daab9aaad48ad47ca4d0b Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Thu, 28 Jul 2016 21:03:26 +0800 Subject: [PATCH 062/207] (feat) Update readme --- README.md | 161 +++++------------------------------------------------- 1 file changed, 13 insertions(+), 148 deletions(-) diff --git a/README.md b/README.md index d954506c8..98166ed58 100644 --- a/README.md +++ b/README.md @@ -2,156 +2,20 @@ ##Introduction - XMemcached is a high performance, easy to use blocking multithreaded memcached client in java. + XMemcached is a high performance, easy to use blocking multithreaded memcached client in java. + It's nio based and was carefully turned to get top performance. -* [Homepage](https://github.com/killme2008/xmemcached) -* [Downloads](https://github.com/killme2008/xmemcached/tags) -* [Wiki](http://code.google.com/p/xmemcached/w/list) -* [Javadoc](http://fnil.net/docs/xmemcached/index.html) +* [Homepage](http://fnil.net/xmemcached/) +* [Wiki](https://github.com/killme2008/xmemcached/wiki) +* [Javadoc](http://fnil.net/docs/xmemcached/index.html) +* [ChangeLog](https://github.com/killme2008/xmemcached/blob/master/NOTICE.txt) -##News and downloads - - * [Xmemcached 2.0.0 released](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.0.0). - - Maven dependency: - - ``` - - com.googlecode.xmemcached - xmemcached - {version} - - ``` - -##Highlights - -* Supports all memcached text based protocols and binary protocols(Binary protocol supports since version 1.2.0). -* Supports distributed memcached with standard hash or consistent hash strategy -* Supports for JMX to allow you to monitor and control the behavior of the XMemcachedClient.Change the optimizer's factor or add/remove memcached server dynamically -* Supports weighted server. -* Supports connection pool.You can create more connections to one memcached server with java nio.(since version 1.2.0) -* Supports failure mode and standby nodes. -* Supports integrating to spring framework and hibernate-memcached. -* High performance. -* Supports talking with kestrel(a MQ written in scala) and TokyoTyrant - - -##FAQ - -###How to build project by maven? - - Type command "mvn -Dtest -DfailIfNoTests=false assembly:assembly" to build the project.Maven will download the dependencies automacly and build project. - - -###How to run unit tests? - - The test.properties file under the src/test/resources folder is used for setting memcached test server. - Please set test.memcached.servers property,Then run the AllTests class with jvm option "-ea". - -###Is Xmemcached compatible with jdk5? - - Yes,since 1.2.0-RC1,Xmemcached is compatible with jdk5. - - -##Example - - //New a XMemcachedClient instance - XMemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddresses("localhost:11211")); - XMemcachedClient client=builder.build(); - - //If you want to use binary protocol - XMemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddresses("localhost:11211")); - builder.setCommandFactory(new BinaryCommandFactory()); - XMemcachedClient client=builder.build(); - - //If you want to use xmemcached talking with kestrel - XMemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddresses("localhost:11211")); - builder.setCommandFactory(new KestrelCommandFactory()); - XMemcachedClient client=builder.build(); - - //If you want to store primitive type as String - client.setPrimitiveAsString(true); - - //Add or remove memcached server dynamically - client.addServer("localhost:12001 localhost:12002"); - client.removeServer("localhost:12001 localhost:12002"); - - - //get operation - String name =client.get("test"); - - //set add replace append prepend gets - client.add("hello", 0, "dennis"); - client.replace("hello", 0, "dennis"); - client.append("hello", 0, " good"); - client.prepend("hello", 0, "hello "); - GetsResponse response=client.gets("hello"); - long cas=response.getCas(); - Obejct value=response.getValue(); - - //incr decr - client.set("a",0,"1"); - client.incr("a",4); - client.decr("a",4); - - //cas - client.cas("a", 0, new CASOperation() { - @Override - public int getMaxTries() { - return 1; //max try times - } - @Override - public Object getNewValue(long currentCAS, Object currentValue) { - System.out.println("current value " + currentValue); - return 3; //return new value to update - } - }); - - //flush_all - client.flushAll(); - - //stats - Map> result=client.getStats(); - - // get server versions - Map version=memcached.getVersions(); - - //bulk get - List keys = new ArrayList(); - keys.add("hello"); - keys.add("test"); - Map map = client.get(keys); - -##Enable jmx support - - java -Dxmemcached.jmx.enable=true [YourApp] - -Access MBean through - - service:jmx:rmi:///jndi/rmi://[host]:7077/xmemcachedServer - -##Integrate to spring framework - - - - localhost:12000 localhost:12001 - - - -##Set server's weight - - //set weight to 2 - client.addServer("localhost",12000,2); - - //or through XMemcachedClientBuilder,pass a weight array to XMemcachedClientBuilder constructor - MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddresses("localhost:12000 localhost:12001"),new int[]{1,3}); - builder.setSessionLocator(new KetamaMemcachedSessionLocator()); - MemcachedClient memcachedClient=builder.build(); - - -More information see [wiki pages](http://code.google.com/p/xmemcached/w/list) please. + +Quick start: + +* [Getting started](https://github.com/killme2008/xmemcached/wiki/Getting%20started) +* [快速入门](https://github.com/killme2008/xmemcached/wiki/%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8) ## Contributors @@ -167,5 +31,6 @@ More information see [wiki pages](http://code.google.com/p/xmemcached/w/list) pl * [spudone](https://github.com/spudone) * [MikeBily](https://github.com/MikeBily) -##License +##License + [Apache License Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html) From 48abba2e7e1c12ddfd09ceb11e149fd977662270 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Mon, 1 Aug 2016 11:51:13 +0800 Subject: [PATCH 063/207] (feat) Remove unnessary volatile declaration --- .../com/google/code/yanf4j/config/Configuration.java | 4 ++-- .../code/yanf4j/core/impl/AbstractController.java | 4 ++-- .../google/code/yanf4j/core/impl/AbstractSession.java | 10 +++++----- .../google/code/yanf4j/core/impl/WriteMessageImpl.java | 2 +- .../java/net/rubyeye/xmemcached/XMemcachedClient.java | 2 +- .../java/net/rubyeye/xmemcached/command/Command.java | 6 +++--- .../xmemcached/impl/KetamaMemcachedSessionLocator.java | 2 +- .../impl/LibmemcachedMemcachedSessionLocator.java | 2 +- .../rubyeye/xmemcached/impl/MemcachedConnector.java | 6 +++--- .../rubyeye/xmemcached/impl/MemcachedTCPSession.java | 2 +- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/google/code/yanf4j/config/Configuration.java b/src/main/java/com/google/code/yanf4j/config/Configuration.java index 0cc9d9a89..1ebb31bb4 100644 --- a/src/main/java/com/google/code/yanf4j/config/Configuration.java +++ b/src/main/java/com/google/code/yanf4j/config/Configuration.java @@ -75,7 +75,7 @@ public class Configuration { /** * check session idle interval */ - private volatile long checkSessionTimeoutInterval = 1000L; + private long checkSessionTimeoutInterval = 1000L; public final int getWriteThreadCount() { return this.writeThreadCount; @@ -94,7 +94,7 @@ public final void setWriteThreadCount(int writeThreadCount) { this.writeThreadCount = writeThreadCount; } - private volatile long sessionIdleTimeout = 5000L; + private long sessionIdleTimeout = 5000L; /** * @see setSessionIdleTimeout diff --git a/src/main/java/com/google/code/yanf4j/core/impl/AbstractController.java b/src/main/java/com/google/code/yanf4j/core/impl/AbstractController.java index b24ad7d08..ea763d19f 100644 --- a/src/main/java/com/google/code/yanf4j/core/impl/AbstractController.java +++ b/src/main/java/com/google/code/yanf4j/core/impl/AbstractController.java @@ -80,7 +80,7 @@ public abstract class AbstractController implements Controller, * Codec Factory */ - protected volatile CodecFactory codecFactory; + protected CodecFactory codecFactory; /** * Status */ @@ -99,7 +99,7 @@ public abstract class AbstractController implements Controller, protected Dispatcher readEventDispatcher, dispatchMessageDispatcher, writeEventDispatcher; protected long sessionTimeout; - protected volatile boolean handleReadWriteConcurrently = true; + protected boolean handleReadWriteConcurrently = true; protected int soTimeout; diff --git a/src/main/java/com/google/code/yanf4j/core/impl/AbstractSession.java b/src/main/java/com/google/code/yanf4j/core/impl/AbstractSession.java index c94719aca..55125e343 100644 --- a/src/main/java/com/google/code/yanf4j/core/impl/AbstractSession.java +++ b/src/main/java/com/google/code/yanf4j/core/impl/AbstractSession.java @@ -64,9 +64,9 @@ public abstract class AbstractSession implements Session { protected Queue writeQueue; - protected volatile long sessionIdleTimeout; + protected long sessionIdleTimeout; - protected volatile long sessionTimeout; + protected long sessionTimeout; public long getSessionIdleTimeout() { return sessionIdleTimeout; @@ -120,9 +120,9 @@ public ReentrantLock getWriteLock() { protected AtomicLong scheduleWritenBytes = new AtomicLong(0); protected final Dispatcher dispatchMessageDispatcher; - protected volatile boolean useBlockingWrite = false; - protected volatile boolean useBlockingRead = true; - protected volatile boolean handleReadWriteConcurrently = true; + protected boolean useBlockingWrite = false; + protected boolean useBlockingRead = true; + protected boolean handleReadWriteConcurrently = true; public abstract void decode(); diff --git a/src/main/java/com/google/code/yanf4j/core/impl/WriteMessageImpl.java b/src/main/java/com/google/code/yanf4j/core/impl/WriteMessageImpl.java index 519c141a7..f5c998413 100644 --- a/src/main/java/com/google/code/yanf4j/core/impl/WriteMessageImpl.java +++ b/src/main/java/com/google/code/yanf4j/core/impl/WriteMessageImpl.java @@ -39,7 +39,7 @@ public class WriteMessageImpl implements WriteMessage { protected FutureImpl writeFuture; - protected volatile boolean writing; + protected boolean writing; public final void writing() { this.writing = true; diff --git a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java index bc0d10e19..98d5c871c 100644 --- a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java +++ b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java @@ -104,7 +104,7 @@ public class XMemcachedClient implements XMemcachedClientMBean, MemcachedClient private String name; // cache name - private volatile boolean failureMode; + private boolean failureMode; private int timeoutExceptionThreshold = DEFAULT_MAX_TIMEOUTEXCEPTION_THRESHOLD; diff --git a/src/main/java/net/rubyeye/xmemcached/command/Command.java b/src/main/java/net/rubyeye/xmemcached/command/Command.java index 1e642a397..ffdd5d301 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/Command.java +++ b/src/main/java/net/rubyeye/xmemcached/command/Command.java @@ -54,13 +54,13 @@ public void setWriteBuffer(com.google.code.yanf4j.buffer.IoBuffer buffers) { protected String key; protected byte[] keyBytes; - protected volatile Object result; + protected Object result; protected CountDownLatch latch; protected CommandType commandType; protected Exception exception; - protected volatile IoBuffer ioBuffer; + protected IoBuffer ioBuffer; protected volatile boolean cancel; - protected volatile OperationStatus status; + protected OperationStatus status; protected int mergeCount = -1; private int copiedMergeCount = mergeCount; @SuppressWarnings("unchecked") diff --git a/src/main/java/net/rubyeye/xmemcached/impl/KetamaMemcachedSessionLocator.java b/src/main/java/net/rubyeye/xmemcached/impl/KetamaMemcachedSessionLocator.java index 2e9548d63..838ae823d 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/KetamaMemcachedSessionLocator.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/KetamaMemcachedSessionLocator.java @@ -52,7 +52,7 @@ public class KetamaMemcachedSessionLocator extends static final int NUM_REPS = 160; private transient volatile TreeMap> ketamaSessions = new TreeMap>(); private final HashAlgorithm hashAlg; - private volatile int maxTries; + private int maxTries; private final Random random = new Random(); /** diff --git a/src/main/java/net/rubyeye/xmemcached/impl/LibmemcachedMemcachedSessionLocator.java b/src/main/java/net/rubyeye/xmemcached/impl/LibmemcachedMemcachedSessionLocator.java index c453bef78..a6e038bb0 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/LibmemcachedMemcachedSessionLocator.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/LibmemcachedMemcachedSessionLocator.java @@ -35,7 +35,7 @@ public class LibmemcachedMemcachedSessionLocator extends static final int DEFAULT_NUM_REPS = 100; private transient volatile TreeMap> ketamaSessions = new TreeMap>(); - private volatile int maxTries; + private int maxTries; private int numReps = DEFAULT_NUM_REPS; private final Random random = new Random(); private HashAlgorithm hashAlgorithm = HashAlgorithm.ONE_AT_A_TIME; diff --git a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java index d238706d4..8e2ee8388 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java @@ -72,12 +72,12 @@ public class MemcachedConnector extends SocketChannelController implements private final Set removedAddrSet = new ConcurrentHashSet(); private final MemcachedOptimizer optimiezer; - private volatile long healSessionInterval = MemcachedClient.DEFAULT_HEAL_SESSION_INTERVAL; + private long healSessionInterval = MemcachedClient.DEFAULT_HEAL_SESSION_INTERVAL; private int connectionPoolSize; // session pool size protected Protocol protocol; - private volatile boolean enableHealSession = true; + private boolean enableHealSession = true; private final CommandFactory commandFactory; - private volatile boolean failureMode; + private boolean failureMode; private final ConcurrentHashMap/* * standby diff --git a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedTCPSession.java b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedTCPSession.java index 0ebd8d39f..628f0e1d3 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedTCPSession.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedTCPSession.java @@ -54,7 +54,7 @@ public class MemcachedTCPSession extends NioTCPSession implements private SocketAddress remoteSocketAddress; // prevent channel is closed private int sendBufferSize; private final MemcachedOptimizer optimiezer; - private volatile boolean allowReconnect; + private boolean allowReconnect; private volatile boolean authFailed; From 4c4ae42706b612a09b2f00b01ac4b4341e408a07 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Mon, 8 Aug 2016 21:33:37 +0800 Subject: [PATCH 064/207] (feat) Smaller read thread count by default. --- src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java index 98d5c871c..f30f0c198 100644 --- a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java +++ b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java @@ -975,7 +975,7 @@ private final void optimiezeSetReadThreadCount(Configuration conf, if (conf != null && addressCount > 1) { if (!this.isWindowsPlatform() && conf.getReadThreadCount() == DEFAULT_READ_THREAD_COUNT) { - int threadCount = 2 * SystemUtils.getSystemThreadCount(); + int threadCount = SystemUtils.getSystemThreadCount(); conf.setReadThreadCount(addressCount > threadCount ? threadCount : addressCount); } From ae6b460c57d087bb837be85c9e6e02cd643f26a3 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Mon, 8 Aug 2016 21:33:52 +0800 Subject: [PATCH 065/207] (feat) Tweak StringEncoder performance. --- .../core/impl/TextLineCodecFactory.java | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/google/code/yanf4j/core/impl/TextLineCodecFactory.java b/src/main/java/com/google/code/yanf4j/core/impl/TextLineCodecFactory.java index 150f58754..93410cd57 100644 --- a/src/main/java/com/google/code/yanf4j/core/impl/TextLineCodecFactory.java +++ b/src/main/java/com/google/code/yanf4j/core/impl/TextLineCodecFactory.java @@ -42,7 +42,8 @@ */ public class TextLineCodecFactory implements CodecFactory { - public static final IoBuffer SPLIT = IoBuffer.wrap("\r\n".getBytes()); + public static final byte [] SPLIT_BS = "\r\n".getBytes(); + public static final IoBuffer SPLIT = IoBuffer.wrap(SPLIT_BS); private static final ByteBufferMatcher SPLIT_PATTERN = new ShiftAndByteBufferMatcher(SPLIT); @@ -85,20 +86,21 @@ public Decoder getDecoder() { } - class StringEncoder implements Encoder { - public IoBuffer encode(Object msg, Session session) { - if (msg == null) { - return null; - } - String message = (String) msg; - ByteBuffer buff = TextLineCodecFactory.this.charset.encode(message); - IoBuffer resultBuffer = IoBuffer.allocate(buff.remaining() + SPLIT.remaining()); - resultBuffer.put(buff); - resultBuffer.put(SPLIT.slice()); - resultBuffer.flip(); - return resultBuffer; - } - } + class StringEncoder implements Encoder { + public IoBuffer encode(Object msg, Session session) { + if (msg == null) { + return null; + } + String message = (String) msg; + ByteBuffer buff = TextLineCodecFactory.this.charset.encode(message); + byte[] bs = new byte[buff.remaining() + SPLIT.remaining()]; + int len = buff.remaining(); + System.arraycopy(buff.array(), buff.position(), bs, 0, len); + System.arraycopy(SPLIT_BS, 0, bs, len, 2); + IoBuffer resultBuffer = IoBuffer.wrap(bs); + return resultBuffer; + } + } private Encoder encoder = new StringEncoder(); @@ -106,5 +108,9 @@ public IoBuffer encode(Object msg, Session session) { public Encoder getEncoder() { return this.encoder; } + + public static void main(String args[] ){ + + } } From 7e00c987aa00996ab886040c8974d258d81c41c3 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Mon, 8 Aug 2016 21:47:18 +0800 Subject: [PATCH 066/207] (feat) Tweak StringEncoder performance. --- .../core/impl/TextLineCodecFactory.java | 100 ++++++++++-------- 1 file changed, 55 insertions(+), 45 deletions(-) diff --git a/src/main/java/com/google/code/yanf4j/core/impl/TextLineCodecFactory.java b/src/main/java/com/google/code/yanf4j/core/impl/TextLineCodecFactory.java index 93410cd57..a40580717 100644 --- a/src/main/java/com/google/code/yanf4j/core/impl/TextLineCodecFactory.java +++ b/src/main/java/com/google/code/yanf4j/core/impl/TextLineCodecFactory.java @@ -32,59 +32,55 @@ import com.google.code.yanf4j.util.ByteBufferMatcher; import com.google.code.yanf4j.util.ShiftAndByteBufferMatcher; - - - /** * Text line codec factory + * * @author dennis * */ public class TextLineCodecFactory implements CodecFactory { - public static final byte [] SPLIT_BS = "\r\n".getBytes(); - public static final IoBuffer SPLIT = IoBuffer.wrap(SPLIT_BS); - - private static final ByteBufferMatcher SPLIT_PATTERN = new ShiftAndByteBufferMatcher(SPLIT); + public static final IoBuffer SPLIT = IoBuffer.wrap("\r\n".getBytes()); - public static final String DEFAULT_CHARSET_NAME = "utf-8"; + private static final ByteBufferMatcher SPLIT_PATTERN = new ShiftAndByteBufferMatcher( + SPLIT); - private Charset charset; + public static final String DEFAULT_CHARSET_NAME = "utf-8"; + private Charset charset; - public TextLineCodecFactory() { - this.charset = Charset.forName(DEFAULT_CHARSET_NAME); - } - - - public TextLineCodecFactory(String charsetName) { - this.charset = Charset.forName(charsetName); - } + public TextLineCodecFactory() { + this.charset = Charset.forName(DEFAULT_CHARSET_NAME); + } - class StringDecoder implements Decoder { - public Object decode(IoBuffer buffer, Session session) { - String result = null; - int index = SPLIT_PATTERN.matchFirst(buffer); - if (index >= 0) { - int limit = buffer.limit(); - buffer.limit(index); - CharBuffer charBuffer = TextLineCodecFactory.this.charset.decode(buffer.buf()); - result = charBuffer.toString(); - buffer.limit(limit); - buffer.position(index + SPLIT.remaining()); + public TextLineCodecFactory(String charsetName) { + this.charset = Charset.forName(charsetName); + } - } - return result; - } - } + class StringDecoder implements Decoder { + public Object decode(IoBuffer buffer, Session session) { + String result = null; + int index = SPLIT_PATTERN.matchFirst(buffer); + if (index >= 0) { + int limit = buffer.limit(); + buffer.limit(index); + CharBuffer charBuffer = TextLineCodecFactory.this.charset + .decode(buffer.buf()); + result = charBuffer.toString(); + buffer.limit(limit); + buffer.position(index + SPLIT.remaining()); - private Decoder decoder = new StringDecoder(); + } + return result; + } + } + private Decoder decoder = new StringDecoder(); - public Decoder getDecoder() { - return this.decoder; + public Decoder getDecoder() { + return this.decoder; - } + } class StringEncoder implements Encoder { public IoBuffer encode(Object msg, Session session) { @@ -96,21 +92,35 @@ public IoBuffer encode(Object msg, Session session) { byte[] bs = new byte[buff.remaining() + SPLIT.remaining()]; int len = buff.remaining(); System.arraycopy(buff.array(), buff.position(), bs, 0, len); - System.arraycopy(SPLIT_BS, 0, bs, len, 2); + bs[len] = 13; // \r + bs[len + 1] = 10; // \n IoBuffer resultBuffer = IoBuffer.wrap(bs); + return resultBuffer; } } - private Encoder encoder = new StringEncoder(); + private Encoder encoder = new StringEncoder(); + public Encoder getEncoder() { + return this.encoder; + } - public Encoder getEncoder() { - return this.encoder; - } - - public static void main(String args[] ){ - - } +// public static void main(String args[]) { +// TextLineCodecFactory codecFactory = new TextLineCodecFactory(); +// Encoder encoder = codecFactory.getEncoder(); +// long sum = 0; +// for (int i = 0; i < 100000; i++) { +// sum += encoder.encode("hello", null).remaining(); +// } +// +// long start = System.currentTimeMillis(); +// +// for (int i = 0; i < 10000000; i++) { +// sum += encoder.encode("hello", null).remaining(); +// } +// long cost = System.currentTimeMillis() - start; +// System.out.println("sum=" + sum + ",cost = " + cost + " ms."); +// } } From 819c416928e98f8fc8be912c3c469551d095edcb Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Mon, 8 Aug 2016 22:21:50 +0800 Subject: [PATCH 067/207] (feat) Tweak fillHeader for BaseBinaryCommand --- .../command/binary/BaseBinaryCommand.java | 104 ++++++++---------- .../BinaryAuthListMechanismsCommand.java | 2 +- .../command/binary/BinaryCASCommand.java | 7 +- .../command/binary/BinaryDeleteCommand.java | 6 +- .../command/binary/BinaryFlushAllCommand.java | 2 +- .../command/binary/BinaryQuitCommand.java | 2 +- .../command/binary/BinaryStatsCommand.java | 10 +- .../binary/BinaryVerbosityCommand.java | 2 +- .../command/binary/BinaryVersionCommand.java | 2 +- .../rubyeye/xmemcached/utils/ByteUtils.java | 64 ++++++++++- 10 files changed, 121 insertions(+), 80 deletions(-) diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BaseBinaryCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BaseBinaryCommand.java index 22ac86ca1..d8ebcaf2b 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BaseBinaryCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BaseBinaryCommand.java @@ -54,7 +54,7 @@ public abstract class BaseBinaryCommand extends Command implements StoreCommand protected OpCode opCode; protected BinaryDecodeStatus decodeStatus = BinaryDecodeStatus.NONE; protected int responseKeyLength, responseExtrasLength, - responseTotalBodyLength; + responseTotalBodyLength; protected ResponseStatus responseStatus; protected int opaque; protected short vbucketId = DEFAULT_VBUCKET_ID; @@ -145,7 +145,7 @@ public boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { } case READ_VALUE: if (this.responseStatus == null - || this.responseStatus == ResponseStatus.NO_ERROR) { + || this.responseStatus == ResponseStatus.NO_ERROR) { if (this.readValue(buffer, this.responseTotalBodyLength, this.responseKeyLength, this.responseExtrasLength)) { this.decodeStatus = BinaryDecodeStatus.DONE; @@ -157,8 +157,8 @@ public boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { // Ignore error message if (ByteUtils.stepBuffer(buffer, this.responseTotalBodyLength - - this.responseKeyLength - - this.responseExtrasLength)) { + - this.responseKeyLength + - this.responseExtrasLength)) { this.decodeStatus = BinaryDecodeStatus.DONE; continue; } else { @@ -271,8 +271,8 @@ protected void readStatus(ByteBuffer buffer) { case INTERNAL_ERROR: case BUSY: case TEMP_FAILURE: - this.setException(new MemcachedServerException( - this.responseStatus.errorMessage())); + this.setException(new MemcachedServerException(this.responseStatus + .errorMessage())); break; } @@ -368,68 +368,56 @@ protected void fillExtras(final CachedData data) { this.ioBuffer.putInt(this.expTime); } - protected final void fillHeader(final CachedData data) { - this.fillMagicNumber(); - this.fillOpCode(); - this.fillKeyLength(); - this.fillExtrasLength(); - this.fillDataType(); - this.fillVbucketId(); - this.fillTotalBodyLength(data); - this.fillOpaque(); - this.fillCAS(); - } - - protected void fillCAS() { - // CAS - this.ioBuffer.putLong(0L); - } - - private void fillOpaque() { + private void fillHeader(final CachedData data) { + byte[] bs = new byte[24]; + bs[0] = REQUEST_MAGIC_NUMBER; + bs[1] = this.opCode.fieldValue(); + short keyLen = getKeyLength(); + bs[2] = ByteUtils.short1(keyLen); + bs[3] = ByteUtils.short0(keyLen); + bs[4] = this.getExtrasLength(); + // dataType,always zero bs[5]=0; + + bs[6] = ByteUtils.short1(this.vbucketId); + bs[7] = ByteUtils.short0(this.vbucketId); + // body len + int bodyLen = this.getExtrasLength() + this.getKeyLength() + + this.getValueLength(data); + bs[8] = ByteUtils.int3(bodyLen); + bs[9] = ByteUtils.int2(bodyLen); + bs[10] = ByteUtils.int1(bodyLen); + bs[11] = ByteUtils.int0(bodyLen); // Opaque if (this.noreply) { this.opaque = OpaqueGenerater.getInstance().getNextValue(); } - this.ioBuffer.putInt(this.opaque); - } - - private void fillTotalBodyLength(final CachedData data) { - this.ioBuffer.putInt(this.getExtrasLength() + this.getKeyLength() - + this.getValueLength(data)); - } - - private void fillVbucketId() { - // vbucketId,valid since memcached 1.6 - this.ioBuffer.putShort(this.vbucketId); - } - - private void fillDataType() { - // Data type - this.ioBuffer.put((byte) 0); - } - - private void fillExtrasLength() { - this.ioBuffer.put(this.getExtrasLength()); - } - - private void fillKeyLength() { - this.ioBuffer.putShort((short) this.getKeyLength()); - } - - private void fillOpCode() { - this.ioBuffer.put(this.opCode.fieldValue()); - } - - private void fillMagicNumber() { - this.ioBuffer.put(REQUEST_MAGIC_NUMBER); + bs[12] = ByteUtils.int3(this.opaque); + bs[13] = ByteUtils.int2(this.opaque); + bs[14] = ByteUtils.int1(this.opaque); + bs[15] = ByteUtils.int0(this.opaque); + // cas + long casValue = getCasValue(); + bs[16] = ByteUtils.long7(casValue); + bs[17] = ByteUtils.long6(casValue); + bs[18] = ByteUtils.long5(casValue); + bs[19] = ByteUtils.long4(casValue); + bs[20] = ByteUtils.long3(casValue); + bs[21] = ByteUtils.long2(casValue); + bs[22] = ByteUtils.long1(casValue); + bs[23] = ByteUtils.long0(casValue); + this.ioBuffer.put(bs); + } + + protected long getCasValue() { + return 0L; } protected int getValueLength(final CachedData data) { return data.getData().length; } - protected int getKeyLength() { - return this.keyBytes.length; + protected short getKeyLength() { + return (short) this.keyBytes.length; } protected byte getExtrasLength() { diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAuthListMechanismsCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAuthListMechanismsCommand.java index 9196acaf6..fe08cbe72 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAuthListMechanismsCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAuthListMechanismsCommand.java @@ -54,7 +54,7 @@ protected void fillKey() { } @Override - protected int getKeyLength() { + protected short getKeyLength() { return 0; } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryCASCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryCASCommand.java index c8dfd9bb2..efe9c8773 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryCASCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryCASCommand.java @@ -53,9 +53,8 @@ public BinaryCASCommand(String key, byte[] keyBytes, CommandType cmdType, } @Override - protected void fillCAS() { - this.ioBuffer.putLong(this.cas); - } - + protected long getCasValue() { + return this.cas; + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryDeleteCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryDeleteCommand.java index 20c99c80c..8e53499a6 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryDeleteCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryDeleteCommand.java @@ -53,11 +53,11 @@ protected void readHeader(ByteBuffer buffer) { } @Override - protected void fillCAS() { + protected long getCasValue(){ if (this.cas > 0) { - this.ioBuffer.putLong(this.cas); + return this.cas; } else { - super.fillCAS(); + return super.getCasValue(); } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryFlushAllCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryFlushAllCommand.java index 64c850c04..3016f3d43 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryFlushAllCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryFlushAllCommand.java @@ -60,7 +60,7 @@ protected byte getExtrasLength() { } @Override - protected int getKeyLength() { + protected short getKeyLength() { return 0; } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryQuitCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryQuitCommand.java index ec57405f1..2e7e251da 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryQuitCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryQuitCommand.java @@ -70,7 +70,7 @@ protected void fillKey() { } @Override - protected int getKeyLength() { + protected short getKeyLength() { return 0; } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryStatsCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryStatsCommand.java index f6dce6f5e..aa30260c2 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryStatsCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryStatsCommand.java @@ -33,8 +33,10 @@ import net.rubyeye.xmemcached.exception.UnknownCommandException; import net.rubyeye.xmemcached.transcoders.CachedData; import net.rubyeye.xmemcached.utils.ByteUtils; + /** * Stats command for binary protocol + * * @author boyan * */ @@ -66,7 +68,7 @@ public BinaryStatsCommand(InetSocketAddress server, CountDownLatch latch, super(null, null, CommandType.STATS, latch, 0, 0, null, false, null); this.server = server; this.itemName = itemName; - this.opCode=OpCode.STAT; + this.opCode = OpCode.STAT; this.result = new HashMap(); } @@ -82,8 +84,6 @@ protected boolean finish() { } } - - @Override protected void readStatus(ByteBuffer buffer) { ResponseStatus responseStatus = ResponseStatus.parseShort(buffer @@ -153,9 +153,9 @@ protected void fillKey() { } @Override - protected int getKeyLength() { + protected short getKeyLength() { if (this.itemName != null) { - return this.itemName.length(); + return (short) this.itemName.length(); } else { return 0; } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryVerbosityCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryVerbosityCommand.java index 6e61be704..049260139 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryVerbosityCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryVerbosityCommand.java @@ -39,7 +39,7 @@ protected byte getExtrasLength() { } @Override - protected int getKeyLength() { + protected short getKeyLength() { return 0; } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryVersionCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryVersionCommand.java index 5dfcb5799..1e93ad5e8 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryVersionCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryVersionCommand.java @@ -90,7 +90,7 @@ protected void fillKey() { } @Override - protected int getKeyLength() { + protected short getKeyLength() { return 0; } diff --git a/src/main/java/net/rubyeye/xmemcached/utils/ByteUtils.java b/src/main/java/net/rubyeye/xmemcached/utils/ByteUtils.java index 4327c20e0..f6eb547fa 100644 --- a/src/main/java/net/rubyeye/xmemcached/utils/ByteUtils.java +++ b/src/main/java/net/rubyeye/xmemcached/utils/ByteUtils.java @@ -248,18 +248,16 @@ public static final boolean stepBuffer(ByteBuffer buffer, int remaining) { } /** - * �峰�涓��琛� + * Read next line from ByteBuffer * * @param buffer + * @return */ public static final String nextLine(ByteBuffer buffer) { if (buffer == null) { return null; } - /** - * 娴��琛ㄦ���� Shift-And绠���归� >BM绠���归���� > �寸��归� > KMP�归�锛� - * 濡��浣���村ソ��缓璁��璇�mail缁��(killme2008@gmail.com) - */ + int index = MemcachedDecoder.SPLIT_MATCHER .matchFirst(com.google.code.yanf4j.buffer.IoBuffer.wrap(buffer)); if (index >= 0) { @@ -447,4 +445,60 @@ public static final int stringSize(long x) { byte_len_array[i & 0xFF] = size; } } + + public static byte int3(int x) { + return (byte) (x >> 24); + } + + public static byte int2(int x) { + return (byte) (x >> 16); + } + + public static byte int1(int x) { + return (byte) (x >> 8); + } + + public static byte int0(int x) { + return (byte) (x); + } + + public static byte short1(short x) { + return (byte) (x >> 8); + } + + public static byte short0(short x) { + return (byte) (x); + } + + public static byte long7(long x) { + return (byte) (x >> 56); + } + + public static byte long6(long x) { + return (byte) (x >> 48); + } + + public static byte long5(long x) { + return (byte) (x >> 40); + } + + public static byte long4(long x) { + return (byte) (x >> 32); + } + + public static byte long3(long x) { + return (byte) (x >> 24); + } + + public static byte long2(long x) { + return (byte) (x >> 16); + } + + public static byte long1(long x) { + return (byte) (x >> 8); + } + + public static byte long0(long x) { + return (byte) (x); + } } From f56d08643a578c59b22fab5bb65583e58e9f4a4f Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Tue, 20 Sep 2016 20:06:03 +0800 Subject: [PATCH 068/207] (feat) Tweak system threads. --- .../code/yanf4j/config/Configuration.java | 21 +++++---- .../google/code/yanf4j/util/SystemUtils.java | 7 ++- .../xmemcached/impl/MemcachedHandler.java | 45 ++++++++++--------- 3 files changed, 43 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/google/code/yanf4j/config/Configuration.java b/src/main/java/com/google/code/yanf4j/config/Configuration.java index 1ebb31bb4..f490bdebe 100644 --- a/src/main/java/com/google/code/yanf4j/config/Configuration.java +++ b/src/main/java/com/google/code/yanf4j/config/Configuration.java @@ -15,6 +15,8 @@ import java.util.concurrent.DelayQueue; +import com.google.code.yanf4j.util.SystemUtils; + /** * Networking configuration * @@ -23,7 +25,7 @@ */ public class Configuration { - public static final String XMEMCACHED_SELECTOR_POOL_SIZE = "xmemcached.selector.pool.size"; + public static final String XMEMCACHED_SELECTOR_POOL_SIZE = "xmemcached.selector.pool.size"; /** * Read buffer size per connection @@ -60,7 +62,10 @@ public class Configuration { */ private int readThreadCount = 1; - private int selectorPoolSize = System.getProperty(XMEMCACHED_SELECTOR_POOL_SIZE) == null ? 2 * Runtime.getRuntime().availableProcessors() : Integer.parseInt(System.getProperty(XMEMCACHED_SELECTOR_POOL_SIZE)); + private int selectorPoolSize = System + .getProperty(XMEMCACHED_SELECTOR_POOL_SIZE) == null ? SystemUtils + .getSystemThreadCount() : Integer.parseInt(System + .getProperty(XMEMCACHED_SELECTOR_POOL_SIZE)); /** * Increasing buffer size per time @@ -184,11 +189,11 @@ public long getCheckSessionTimeoutInterval() { return this.checkSessionTimeoutInterval; } - public void setSelectorPoolSize(int selectorPoolSize) { - this.selectorPoolSize = selectorPoolSize; - } + public void setSelectorPoolSize(int selectorPoolSize) { + this.selectorPoolSize = selectorPoolSize; + } - public int getSelectorPoolSize() { - return selectorPoolSize; - } + public int getSelectorPoolSize() { + return selectorPoolSize; + } } diff --git a/src/main/java/com/google/code/yanf4j/util/SystemUtils.java b/src/main/java/com/google/code/yanf4j/util/SystemUtils.java index 5da74fcbd..56e92db09 100644 --- a/src/main/java/com/google/code/yanf4j/util/SystemUtils.java +++ b/src/main/java/com/google/code/yanf4j/util/SystemUtils.java @@ -95,7 +95,12 @@ public static void main(String[] args) { } public static final int getSystemThreadCount() { - return getCpuProcessorCount(); + int cpus = getCpuProcessorCount(); + if (cpus <= 8) { + return cpus; + } else { + return 8 + (cpus - 8) * 5 / 8; + } } public static final int getCpuProcessorCount() { diff --git a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java index cd82d0c14..bff5370e0 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java @@ -57,7 +57,9 @@ */ public class MemcachedHandler extends HandlerAdapter { - private static final int MAX_HEARTBEAT_THREADS = Integer.parseInt(System.getProperty("xmemcached.heartbeat.max_threads", String.valueOf(Runtime.getRuntime().availableProcessors()))); + private static final int MAX_HEARTBEAT_THREADS = Integer.parseInt(System + .getProperty("xmemcached.heartbeat.max_threads", + String.valueOf(SystemUtils.getSystemThreadCount()))); private final StatisticsHandler statisticsHandler; @@ -291,26 +293,27 @@ public void stop() { final long HEARTBEAT_PERIOD = Long.parseLong(System.getProperty( "xmemcached.heartbeat.period", "5000")); - public void start() { - final String name = "XMemcached-HeartBeatPool[" + client.getName() + "]"; - final AtomicInteger threadCounter = new AtomicInteger(); - - long keepAliveTime = client.getConnector().getSessionIdleTimeout() * 3 / 2; - - this.heartBeatThreadPool = new ThreadPoolExecutor(1, MAX_HEARTBEAT_THREADS, - keepAliveTime, TimeUnit.MILLISECONDS, - new SynchronousQueue(), - new ThreadFactory() { - public Thread newThread(Runnable r) { - Thread t = new Thread(r, name + "-" + threadCounter.getAndIncrement()); - t.setDaemon(true); - if (t.getPriority() != Thread.NORM_PRIORITY) { - t.setPriority(Thread.NORM_PRIORITY); - } - return t; - } - }, new ThreadPoolExecutor.DiscardPolicy()); - } + public void start() { + final String name = "XMemcached-HeartBeatPool[" + client.getName() + + "]"; + final AtomicInteger threadCounter = new AtomicInteger(); + + long keepAliveTime = client.getConnector().getSessionIdleTimeout() * 3 / 2; + + this.heartBeatThreadPool = new ThreadPoolExecutor(1, + MAX_HEARTBEAT_THREADS, keepAliveTime, TimeUnit.MILLISECONDS, + new SynchronousQueue(), new ThreadFactory() { + public Thread newThread(Runnable r) { + Thread t = new Thread(r, name + "-" + + threadCounter.getAndIncrement()); + t.setDaemon(true); + if (t.getPriority() != Thread.NORM_PRIORITY) { + t.setPriority(Thread.NORM_PRIORITY); + } + return t; + } + }, new ThreadPoolExecutor.DiscardPolicy()); + } public MemcachedHandler(MemcachedClient client) { super(); From d14fc8144b40238e4ef633738eebc77d95455542 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Fri, 23 Sep 2016 11:15:21 +0800 Subject: [PATCH 069/207] (fix) Resolve hostName again when reconnecting, close #49 --- .../utils/InetSocketAddressWrapper.java | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/rubyeye/xmemcached/utils/InetSocketAddressWrapper.java b/src/main/java/net/rubyeye/xmemcached/utils/InetSocketAddressWrapper.java index 9667191b6..853fce18e 100644 --- a/src/main/java/net/rubyeye/xmemcached/utils/InetSocketAddressWrapper.java +++ b/src/main/java/net/rubyeye/xmemcached/utils/InetSocketAddressWrapper.java @@ -13,6 +13,8 @@ public class InetSocketAddressWrapper { private int order; // The address order in list private int weight; // The weight of this address private volatile String remoteAddressStr; + private volatile String hostName; + private volatile String mainNodeHostName; /** * Main memcached node address,if this is a main node,then this value is * null. @@ -22,10 +24,10 @@ public class InetSocketAddressWrapper { public InetSocketAddressWrapper(InetSocketAddress inetSocketAddress, int order, int weight, InetSocketAddress mainNodeAddress) { super(); - this.inetSocketAddress = inetSocketAddress; + setInetSocketAddress(inetSocketAddress); + setMainNodeAddress(mainNodeAddress); this.order = order; this.weight = weight; - this.mainNodeAddress = mainNodeAddress; } public String getRemoteAddressStr() { @@ -37,11 +39,24 @@ public void setRemoteAddressStr(String remoteAddressStr) { } public final InetSocketAddress getInetSocketAddress() { - return this.inetSocketAddress; + if (isValidHostName(this.hostName)) { + // If it has a hostName, we try to resolve it again. + return new InetSocketAddress(this.hostName, + this.inetSocketAddress.getPort()); + } else { + return this.inetSocketAddress; + } + } + + private boolean isValidHostName(String h) { + return h != null && h.trim().length() > 0; } public final void setInetSocketAddress(InetSocketAddress inetSocketAddress) { this.inetSocketAddress = inetSocketAddress; + if (inetSocketAddress != null) { + this.hostName = inetSocketAddress.getHostName(); + } } public final int getOrder() { @@ -57,11 +72,19 @@ public void setWeight(int weight) { } public InetSocketAddress getMainNodeAddress() { - return this.mainNodeAddress; + if (this.isValidHostName(this.mainNodeHostName)) { + return new InetSocketAddress(this.mainNodeHostName, + this.mainNodeAddress.getPort()); + } else { + return this.mainNodeAddress; + } } public void setMainNodeAddress(InetSocketAddress mainNodeAddress) { this.mainNodeAddress = mainNodeAddress; + if (mainNodeAddress != null) { + this.mainNodeHostName = mainNodeAddress.getHostName(); + } } public final void setOrder(int order) { From 5b36a8cd3b2dac85b7dcfa3478e11222f66f0e61 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Mon, 26 Sep 2016 20:17:21 +0800 Subject: [PATCH 070/207] (feat) Improve getMulti0 --- .../rubyeye/xmemcached/XMemcachedClient.java | 9 +- .../rubyeye/xmemcached/impl/Optimizer.java | 2 +- .../rubyeye/xmemcached/utils/ByteUtils.java | 7 ++ .../xmemcached/utils/CachedString.java | 98 +++++++++++++++++++ ...{OptimezerTest.java => OptimizerTest.java} | 4 +- 5 files changed, 112 insertions(+), 8 deletions(-) create mode 100644 src/main/java/net/rubyeye/xmemcached/utils/CachedString.java rename src/test/java/net/rubyeye/xmemcached/test/unittest/impl/{OptimezerTest.java => OptimizerTest.java} (96%) diff --git a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java index f30f0c198..78cf11d18 100644 --- a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java +++ b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java @@ -1315,13 +1315,12 @@ private final Collection> catalogKeys( for (String key : keyCollections) { Session index = this.sessionLocator.getSessionByKey(key); - if (!catalogMap.containsKey(index)) { - List tmpKeys = new ArrayList(100); - tmpKeys.add(key); + List tmpKeys = catalogMap.get(index); + if (tmpKeys == null) { + tmpKeys = new ArrayList(10); catalogMap.put(index, tmpKeys); - } else { - catalogMap.get(index).add(key); } + tmpKeys.add(key); } Collection> catalogKeys = catalogMap.values(); diff --git a/src/main/java/net/rubyeye/xmemcached/impl/Optimizer.java b/src/main/java/net/rubyeye/xmemcached/impl/Optimizer.java index 56c513690..5c78f355f 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/Optimizer.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/Optimizer.java @@ -148,7 +148,7 @@ public final Command optimiezeMergeBuffer(Command optimiezeCommand, log.debug("Optimieze merge buffer:" + optimiezeCommand.toString()); } if (this.optimiezeMergeBuffer - && optimiezeCommand.getIoBuffer().remaining() < sendBufferSize) { + && optimiezeCommand.getIoBuffer().remaining() < sendBufferSize - 24) { optimiezeCommand = this.mergeBuffer(optimiezeCommand, writeQueue, executingCmds, sendBufferSize); } diff --git a/src/main/java/net/rubyeye/xmemcached/utils/ByteUtils.java b/src/main/java/net/rubyeye/xmemcached/utils/ByteUtils.java index f6eb547fa..56f935fab 100644 --- a/src/main/java/net/rubyeye/xmemcached/utils/ByteUtils.java +++ b/src/main/java/net/rubyeye/xmemcached/utils/ByteUtils.java @@ -35,6 +35,10 @@ public final class ByteUtils { public static final Charset DEFAULT_CHARSET = Charset .forName(DEFAULT_CHARSET_NAME); public static final ByteBuffer SPLIT = ByteBuffer.wrap(Constants.CRLF); + + public static final boolean ENABLE_CACHED_STRING_BYTES = Boolean + .valueOf(System.getProperty( + "xmemcached.string.bytes.cached.enable", "false")); /** * if it is testing,check key argument even if use binary protocol. The user * must never change this value at all. @@ -68,6 +72,9 @@ public static final byte[] getBytes(String k) { if (k == null || k.length() == 0) { throw new IllegalArgumentException("Key must not be blank"); } + if (ENABLE_CACHED_STRING_BYTES) { + return CachedString.getBytes(k); + } try { return k.getBytes(DEFAULT_CHARSET_NAME); } catch (UnsupportedEncodingException e) { diff --git a/src/main/java/net/rubyeye/xmemcached/utils/CachedString.java b/src/main/java/net/rubyeye/xmemcached/utils/CachedString.java new file mode 100644 index 000000000..431c08f92 --- /dev/null +++ b/src/main/java/net/rubyeye/xmemcached/utils/CachedString.java @@ -0,0 +1,98 @@ +package net.rubyeye.xmemcached.utils; + +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.util.Arrays; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import javax.management.RuntimeErrorException; + +public class CachedString { + private static ConcurrentHashMap> table = new ConcurrentHashMap(); + static final ReferenceQueue rq = new ReferenceQueue(); + + public static byte[] getBytes(String s) { + if (s == null || s.length() == 0) + return null; + byte[] bs = null; + Reference existingRef = table.get(s); + if (existingRef == null) { + clearCache(rq, table); + bs = s.getBytes(ByteUtils.DEFAULT_CHARSET); + existingRef = table.putIfAbsent(s, + new WeakReference(bs, rq)); + } + if (existingRef == null) { + return bs; + } + byte[] existingbs = existingRef.get(); + if (existingbs != null) { + return existingbs; + } + // entry died in the interim, do over + table.remove(s, existingRef); + return getBytes(s); + } + + static public void clearCache(ReferenceQueue rq, + ConcurrentHashMap> cache) { + // cleanup any dead entries + if (rq.poll() != null) { + while (rq.poll() != null) + ; + for (Map.Entry> e : cache.entrySet()) { + Reference val = e.getValue(); + if (val != null && val.get() == null) { + cache.remove(e.getKey(), val); + } + } + } + } + + private static long testString(int keyLen) { + String k = getKey(keyLen); + long len = 0; + for (int i = 0; i < 1000; i++) { + // byte[] bs = k.getBytes(ByteUtils.DEFAULT_CHARSET); + // String nk = new String(bs, ByteUtils.DEFAULT_CHARSET); + byte[] bs = getBytes(k); + String nk = ByteUtils.getString(bs); + if (!k.equals(nk)) { + throw new RuntimeException(); + } + len += nk.length(); + } + return len; + } + + private static String getKey(int len) { + StringBuilder sb = new StringBuilder(); + String[] chars = { "a", "b", "c", "d", "e", "f", "g", "h" }; + int index = (int) Math.floor(Math.random() * 8); + for (int i = 0; i < len; i++) { + sb.append(chars[index]); + } + return sb.toString(); + } + + public static void main(String[] args) { + long sum = 0; + for (int i = 0; i < 10000; i++) { + sum += testString(8); + } + int[] keys = { 8, 64, 128 }; + + for (int k : keys) { + long start = System.currentTimeMillis(); + for (int i = 0; i < 100000; i++) { + sum += testString(k); + } + System.out.println("Key length=" + k + ", cost " + + (System.currentTimeMillis() - start) + " ms."); + } + System.out.println(sum); + System.out.println(table.size()); + } +} diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/OptimezerTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/OptimizerTest.java similarity index 96% rename from src/test/java/net/rubyeye/xmemcached/test/unittest/impl/OptimezerTest.java rename to src/test/java/net/rubyeye/xmemcached/test/unittest/impl/OptimizerTest.java index 9aef484fc..9fbff8444 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/OptimezerTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/OptimizerTest.java @@ -24,7 +24,7 @@ import com.google.code.yanf4j.util.SimpleQueue; @SuppressWarnings("unchecked") -public class OptimezerTest extends TestCase { +public class OptimizerTest extends TestCase { Optimizer optimiezer; Queue writeQueue; @@ -254,7 +254,7 @@ public void testMergeLimitBuffer() { // set send buffer size to 30,merge four commands at most this.optimiezer.setOptimizeMergeBuffer(true); Command optimiezeCommand = this.optimiezer.optimiezeMergeBuffer( - this.currentCmd, this.writeQueue, this.executingCmds, 30); + this.currentCmd, this.writeQueue, this.executingCmds, 54); assertNotSame(this.currentCmd, optimiezeCommand); ByteBuffer mergeBuffer = optimiezeCommand.getIoBuffer().buf(); assertEquals(0, this.writeQueue.size()); From 8d52950d5629428935e74d0c45457bd49dd62336 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Tue, 27 Sep 2016 00:43:14 +0800 Subject: [PATCH 071/207] [maven-release-plugin] prepare release xmemcached-2.1.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1edb40bee..cf9b90c3d 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ 4.0.0 com.googlecode.xmemcached xmemcached - 2.0.2-SNAPSHOT + 2.1.0 xmemcached Extreme performance modern memcached client for java https://github.com/killme2008/xmemcached From da4cc831b15ef137d5d790c102d7cc41a112c2cd Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Tue, 27 Sep 2016 00:43:41 +0800 Subject: [PATCH 072/207] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index cf9b90c3d..a6b0001a2 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ 4.0.0 com.googlecode.xmemcached xmemcached - 2.1.0 + 2.1.1-SNAPSHOT xmemcached Extreme performance modern memcached client for java https://github.com/killme2008/xmemcached From 6d6cd8ffea122f06570e4c85adae4e4dcd6a6943 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Sat, 1 Oct 2016 19:55:04 +0800 Subject: [PATCH 073/207] (fix) Fixed decoding command may block recator thread, close #30. --- .../yanf4j/nio/impl/AbstractNioSession.java | 2 +- .../rubyeye/xmemcached/command/Command.java | 10 +++++++ .../xmemcached/impl/MemcachedHandler.java | 10 +++---- .../xmemcached/impl/MemcachedTCPSession.java | 10 ++++++- .../impl/MemcachedHandlerUnitTest.java | 28 +++++++++---------- 5 files changed, 39 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/google/code/yanf4j/nio/impl/AbstractNioSession.java b/src/main/java/com/google/code/yanf4j/nio/impl/AbstractNioSession.java index 556cbc395..14169673f 100644 --- a/src/main/java/com/google/code/yanf4j/nio/impl/AbstractNioSession.java +++ b/src/main/java/com/google/code/yanf4j/nio/impl/AbstractNioSession.java @@ -95,7 +95,7 @@ protected void onWrite(SelectionKey key) { isLockedByMe = true; WriteMessage currentMessage = null; - // make read/write fail, write/read=3/2 + // make read/write fail, write/read=2/1 final long maxWritten = readBuffer.capacity() + readBuffer.capacity() >>> 1; try { long written = 0; diff --git a/src/main/java/net/rubyeye/xmemcached/command/Command.java b/src/main/java/net/rubyeye/xmemcached/command/Command.java index ffdd5d301..71abadf93 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/Command.java +++ b/src/main/java/net/rubyeye/xmemcached/command/Command.java @@ -39,6 +39,16 @@ public abstract class Command implements WriteMessage { public static final byte REQUEST_MAGIC_NUMBER = (byte) (0x80 & 0xFF); public static final byte RESPONSE_MAGIC_NUMBER = (byte) (0x81 & 0xFF); + + private boolean added; + + public boolean isAdded() { + return added; + } + + public void setAdded(boolean added) { + this.added = added; + } public final Object getMessage() { return this; diff --git a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java index bff5370e0..311f58cb3 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java @@ -118,18 +118,18 @@ public void setEnableHeartBeat(boolean enableHeartBeat) { public final void onMessageSent(Session session, Object msg) { Command command = (Command) msg; command.setStatus(OperationStatus.SENT); - if (!command.isNoreply() - || this.client.getProtocol() == Protocol.Binary) { - ((MemcachedTCPSession) session).addCommand(command); - } // After message sent,we can set the buffer to be null for gc friendly. command.setIoBuffer(EMPTY_BUF); switch (command.getCommandType()) { + case ADD: + case APPEND: case SET: case SET_MANY: // After message sent,we can set the value to be null for gc // friendly. - ((StoreCommand) command).setValue(null); + if (command instanceof StoreCommand) { + ((StoreCommand) command).setValue(null); + } break; } } diff --git a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedTCPSession.java b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedTCPSession.java index 628f0e1d3..590f47d51 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedTCPSession.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedTCPSession.java @@ -28,6 +28,7 @@ import net.rubyeye.xmemcached.exception.MemcachedException; import net.rubyeye.xmemcached.networking.MemcachedSession; import net.rubyeye.xmemcached.utils.InetSocketAddressWrapper; +import net.rubyeye.xmemcached.utils.Protocol; import com.google.code.yanf4j.core.WriteMessage; import com.google.code.yanf4j.core.impl.FutureImpl; @@ -144,13 +145,20 @@ protected WriteMessage preprocessWriteMessage(WriteMessage writeMessage) { } if (currentCommand.getStatus() == OperationStatus.SENDING) { /** - * optimieze commands + * optimize commands */ currentCommand = this.optimiezer.optimize(currentCommand, this.writeQueue, this.commandAlreadySent, this.sendBufferSize); } + currentCommand.setStatus(OperationStatus.WRITING); + if ((!currentCommand.isNoreply() || this.commandFactory.getProtocol() == Protocol.Binary) + && !currentCommand.isAdded()) { + currentCommand.setAdded(true); + this.addCommand(currentCommand); + } + return currentCommand; } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/MemcachedHandlerUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/MemcachedHandlerUnitTest.java index 5cbfce754..13a9e20df 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/MemcachedHandlerUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/MemcachedHandlerUnitTest.java @@ -6,6 +6,7 @@ import net.rubyeye.xmemcached.MemcachedClient; import net.rubyeye.xmemcached.command.Command; import net.rubyeye.xmemcached.command.CommandType; +import net.rubyeye.xmemcached.command.OperationStatus; import net.rubyeye.xmemcached.command.binary.BinaryStoreCommand; import net.rubyeye.xmemcached.command.binary.BinaryVersionCommand; import net.rubyeye.xmemcached.command.text.TextStoreCommand; @@ -16,6 +17,7 @@ import org.easymock.classextension.EasyMock; import org.easymock.classextension.IMocksControl; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -41,45 +43,43 @@ public void setUp() { public void testOnMessageSent_TextCommand() { Command cmd = new TextVersionCommand(new CountDownLatch(1), new InetSocketAddress(8080)); - this.session.addCommand(cmd); - EasyMock.expectLastCall(); this.mocksControl.replay(); this.handler.onMessageSent(this.session, cmd); this.mocksControl.verify(); + Assert.assertEquals(cmd.getStatus(), OperationStatus.SENT); } @Test public void testOnMessageSent_TextCommand_NoReply() { - Command cmd = new TextStoreCommand(null, null, CommandType.SET, null, 1, 1, null, - true, null); - EasyMock.expect(this.memcachedClient.getProtocol()).andReturn( - Protocol.Text); + TextStoreCommand cmd = new TextStoreCommand(null, null, + CommandType.SET, null, 1, 1, "hello", true, null); + Assert.assertEquals("hello", cmd.getValue()); this.mocksControl.replay(); this.handler.onMessageSent(this.session, cmd); this.mocksControl.verify(); + Assert.assertEquals(cmd.getStatus(), OperationStatus.SENT); + Assert.assertNull(cmd.getValue()); } @Test public void testOnMessageSent_BinaryCommand() { Command cmd = new BinaryVersionCommand(null, null); - this.session.addCommand(cmd); - EasyMock.expectLastCall(); this.mocksControl.replay(); this.handler.onMessageSent(this.session, cmd); this.mocksControl.verify(); + Assert.assertEquals(cmd.getStatus(), OperationStatus.SENT); } @Test public void testOnMessageSent_BinaryCommand_NoReply() { - Command cmd = new BinaryStoreCommand(null, null, CommandType.ADD, null, - 1, 1, null, true, null); - EasyMock.expect(this.memcachedClient.getProtocol()).andReturn( - Protocol.Binary); - this.session.addCommand(cmd); - EasyMock.expectLastCall(); + BinaryStoreCommand cmd = new BinaryStoreCommand(null, null, + CommandType.ADD, null, 1, 1, "hello", true, null); + Assert.assertEquals("hello", cmd.getValue()); this.mocksControl.replay(); this.handler.onMessageSent(this.session, cmd); this.mocksControl.verify(); + Assert.assertEquals(cmd.getStatus(), OperationStatus.SENT); + Assert.assertNull(cmd.getValue()); } } From a68e43108c45b0863e496ec37d559cd20c838bb2 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Sat, 1 Oct 2016 20:06:16 +0800 Subject: [PATCH 074/207] (feat) Add test for #30 --- .../yanf4j/nio/impl/AbstractNioSession.java | 2 +- .../xmemcached/impl/MemcachedTCPSession.java | 5 +- .../StandardHashMemcachedClientIT.java | 61 ++++++++++++++++--- 3 files changed, 58 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/google/code/yanf4j/nio/impl/AbstractNioSession.java b/src/main/java/com/google/code/yanf4j/nio/impl/AbstractNioSession.java index 14169673f..69ec6283c 100644 --- a/src/main/java/com/google/code/yanf4j/nio/impl/AbstractNioSession.java +++ b/src/main/java/com/google/code/yanf4j/nio/impl/AbstractNioSession.java @@ -95,7 +95,7 @@ protected void onWrite(SelectionKey key) { isLockedByMe = true; WriteMessage currentMessage = null; - // make read/write fail, write/read=2/1 + final long maxWritten = readBuffer.capacity() + readBuffer.capacity() >>> 1; try { long written = 0; diff --git a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedTCPSession.java b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedTCPSession.java index 590f47d51..dbb65cab3 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedTCPSession.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedTCPSession.java @@ -153,8 +153,9 @@ protected WriteMessage preprocessWriteMessage(WriteMessage writeMessage) { } currentCommand.setStatus(OperationStatus.WRITING); - if ((!currentCommand.isNoreply() || this.commandFactory.getProtocol() == Protocol.Binary) - && !currentCommand.isAdded()) { + if (!currentCommand.isAdded() + && (!currentCommand.isNoreply() || this.commandFactory + .getProtocol() == Protocol.Binary)) { currentCommand.setAdded(true); this.addCommand(currentCommand); } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/StandardHashMemcachedClientIT.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/StandardHashMemcachedClientIT.java index 2a0d05a04..1c1058726 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/StandardHashMemcachedClientIT.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/StandardHashMemcachedClientIT.java @@ -2,14 +2,20 @@ import java.net.InetSocketAddress; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; +import org.junit.Assert; +import org.junit.Test; + import net.rubyeye.xmemcached.CASOperation; import net.rubyeye.xmemcached.GetsResponse; import net.rubyeye.xmemcached.MemcachedClientBuilder; import net.rubyeye.xmemcached.XMemcachedClientBuilder; +import net.rubyeye.xmemcached.exception.MemcachedServerException; import net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator; +import net.rubyeye.xmemcached.transcoders.SerializingTranscoder; import net.rubyeye.xmemcached.transcoders.StringTranscoder; import net.rubyeye.xmemcached.utils.AddrUtil; @@ -17,13 +23,56 @@ public class StandardHashMemcachedClientIT extends XMemcachedClientIT { @Override public MemcachedClientBuilder createBuilder() throws Exception { - MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil - .getAddresses(this.properties + MemcachedClientBuilder builder = new XMemcachedClientBuilder( + AddrUtil.getAddresses(this.properties .getProperty("test.memcached.servers"))); - //builder.setConnectionPoolSize(Runtime.getRuntime().availableProcessors()); + // builder.setConnectionPoolSize(Runtime.getRuntime().availableProcessors()); return builder; } - + + private static final String KEY_LARGE_OBJECT = "largeObject"; + + @Test + public void testLargeObject() throws Exception { + int megabyte_plus1 = 1048577; // 1024 * 1024 + 1 + SerializingTranscoder transcoder = new SerializingTranscoder( + megabyte_plus1 * 2); // something bigger than memcached daemon + // max value size. + transcoder.setCompressionThreshold(transcoder.getMaxSize()); // bumping + // up + // compression + // threshold + // so + // that + // xmemcached + // client + // does + // not + // compress. + + for (int i = 0; i < 5; i++) { + try { + String largeObject = createString(megabyte_plus1); + + this.memcachedClient.set(KEY_LARGE_OBJECT, 60, largeObject, + transcoder); + fail(); + + } catch (MemcachedServerException exception) { + Assert.assertTrue(exception.getMessage().contains( + "object too large for cache")); + } + } + String readLargeObject = memcachedClient.get(KEY_LARGE_OBJECT); + assertNull(readLargeObject); + } + + private static String createString(int size) { + char[] chars = new char[size]; + Arrays.fill(chars, 'f'); + return new String(chars); + } + public void testStoreNoReply() throws Exception { memcachedClient.replaceWithNoReply("name", 0, 1); assertNull(memcachedClient.get("name")); @@ -93,7 +142,6 @@ public Integer getNewValue(long currentCAS, Integer currentValue) { assertEquals(3, memcachedClient.get("a")); } - public void testDeleteWithNoReply() throws Exception { assertTrue(memcachedClient.set("name", 0, "dennis")); assertEquals("dennis", memcachedClient.get("name")); @@ -109,7 +157,7 @@ public void testDeleteWithNoReply() throws Exception { assertTrue(memcachedClient.add("name", 0, "zhuang")); assertTrue(memcachedClient.replace("name", 0, "zhuang")); } - + public void testFlushAllWithNoReply() throws Exception { for (int i = 0; i < 10; i++) { assertTrue(memcachedClient.add(String.valueOf(i), 0, i)); @@ -147,7 +195,6 @@ public void testDecrWithNoReply() throws Exception { assertEquals("46", memcachedClient.get("a")); } - @Override public MemcachedClientBuilder createWeightedBuilder() throws Exception { List addressList = AddrUtil From 73f622fdfab60cc96beb15f0bd6f16e1019d1a23 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Sun, 9 Oct 2016 11:02:50 +0800 Subject: [PATCH 075/207] (fix) Heartbeating failure counter error --- .../net/rubyeye/xmemcached/impl/MemcachedHandler.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java index 311f58cb3..406e6c1d2 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java @@ -237,12 +237,13 @@ public void run() { if (!this.versionCommand.getLatch().await(2000, TimeUnit.MILLISECONDS)) { heartBeatFailCount.incrementAndGet(); - } - if (this.versionCommand.getResult() == null) { - heartBeatFailCount.incrementAndGet(); } else { - // reset - heartBeatFailCount.set(0); + if (this.versionCommand.getResult() == null) { + heartBeatFailCount.incrementAndGet(); + } else { + // reset the failure counter + heartBeatFailCount.set(0); + } } if (heartBeatFailCount.get() > MAX_HEART_BEAT_FAIL_COUNT) { log.warn("Session(" From 8e98a6a87bf120409edfbdf66d380a0bb25efaa5 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Sat, 15 Oct 2016 16:11:31 +0800 Subject: [PATCH 076/207] (feat) Remove the supporting for hibernate-memcached --- pom.xml | 15 -- .../xmemcached/utils/hibernate/Xmemcache.java | 110 ----------- .../hibernate/XmemcachedClientFactory.java | 172 ------------------ .../xmemcached/utils/hibernate/package.html | 14 -- .../XmemcacheClientFactoryUnitIT.java | 78 -------- 5 files changed, 389 deletions(-) delete mode 100644 src/main/java/net/rubyeye/xmemcached/utils/hibernate/Xmemcache.java delete mode 100644 src/main/java/net/rubyeye/xmemcached/utils/hibernate/XmemcachedClientFactory.java delete mode 100644 src/main/java/net/rubyeye/xmemcached/utils/hibernate/package.html delete mode 100644 src/test/java/net/rubyeye/xmemcached/test/unittest/hibernate/XmemcacheClientFactoryUnitIT.java diff --git a/pom.xml b/pom.xml index a6b0001a2..ee22bd7f2 100644 --- a/pom.xml +++ b/pom.xml @@ -78,7 +78,6 @@ 1.7.5 2.5 - 1.2 1.1 1.2.16 4.12 @@ -204,20 +203,6 @@ ${spring.version} provided - - com.googlecode - hibernate-memcached - ${hibernate.memcached.version} - provided - - - javax.transaction - jta - - - - javax.transaction jta diff --git a/src/main/java/net/rubyeye/xmemcached/utils/hibernate/Xmemcache.java b/src/main/java/net/rubyeye/xmemcached/utils/hibernate/Xmemcache.java deleted file mode 100644 index 77af60673..000000000 --- a/src/main/java/net/rubyeye/xmemcached/utils/hibernate/Xmemcache.java +++ /dev/null @@ -1,110 +0,0 @@ -/** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 - */ -/** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 net.rubyeye.xmemcached.utils.hibernate; - -import java.util.Arrays; -import java.util.Map; - -import net.rubyeye.xmemcached.MemcachedClient; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.googlecode.hibernate.memcached.LoggingMemcacheExceptionHandler; -import com.googlecode.hibernate.memcached.Memcache; -import com.googlecode.hibernate.memcached.MemcacheExceptionHandler; -import com.googlecode.hibernate.memcached.utils.StringUtils; -/** - * Hibernate memcached implementation - * @author boyan - * - */ -public class Xmemcache implements Memcache { - private static final Logger log = LoggerFactory.getLogger(Xmemcache.class); - private MemcacheExceptionHandler exceptionHandler = new LoggingMemcacheExceptionHandler(); - - private final MemcachedClient memcachedClient; - - public Xmemcache(MemcachedClient memcachedClient) { - this.memcachedClient = memcachedClient; - } - - public Object get(String key) { - try { - log.debug("MemcachedClient.get({})", key); - return this.memcachedClient.get(key); - } catch (Exception e) { - this.exceptionHandler.handleErrorOnGet(key, e); - } - return null; - } - - public Map getMulti(String... keys) { - try { - return this.memcachedClient.get(Arrays.asList(keys)); - } catch (Exception e) { - this.exceptionHandler.handleErrorOnGet( - StringUtils.join(keys, ", "), e); - } - return null; - } - - public void set(String key, int cacheTimeSeconds, Object o) { - log.debug("MemcachedClient.set({})", key); - try { - this.memcachedClient.set(key, cacheTimeSeconds, o); - } catch (Exception e) { - this.exceptionHandler.handleErrorOnSet(key, cacheTimeSeconds, o, e); - } - } - - public void delete(String key) { - try { - this.memcachedClient.delete(key); - } catch (Exception e) { - this.exceptionHandler.handleErrorOnDelete(key, e); - } - } - - public void incr(String key, int factor, int startingValue) { - try { - this.memcachedClient.incr(key, factor, startingValue); - } catch (Exception e) { - this.exceptionHandler.handleErrorOnIncr(key, factor, startingValue, - e); - } - } - - public void shutdown() { - log.debug("Shutting down XMemcachedClient"); - try { - this.memcachedClient.shutdown(); - } catch (Exception e) { - log.error("Shut down XMemcachedClient error", e); - } - - } - - public void setExceptionHandler(MemcacheExceptionHandler exceptionHandler) { - this.exceptionHandler = exceptionHandler; - } -} diff --git a/src/main/java/net/rubyeye/xmemcached/utils/hibernate/XmemcachedClientFactory.java b/src/main/java/net/rubyeye/xmemcached/utils/hibernate/XmemcachedClientFactory.java deleted file mode 100644 index 86ff5302d..000000000 --- a/src/main/java/net/rubyeye/xmemcached/utils/hibernate/XmemcachedClientFactory.java +++ /dev/null @@ -1,172 +0,0 @@ -/** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 - */ -/** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 net.rubyeye.xmemcached.utils.hibernate; - -import net.rubyeye.xmemcached.CommandFactory; -import net.rubyeye.xmemcached.HashAlgorithm; -import net.rubyeye.xmemcached.MemcachedClient; -import net.rubyeye.xmemcached.MemcachedClientBuilder; -import net.rubyeye.xmemcached.MemcachedSessionLocator; -import net.rubyeye.xmemcached.XMemcachedClientBuilder; -import net.rubyeye.xmemcached.command.BinaryCommandFactory; -import net.rubyeye.xmemcached.command.TextCommandFactory; -import net.rubyeye.xmemcached.impl.ArrayMemcachedSessionLocator; -import net.rubyeye.xmemcached.impl.PHPMemcacheSessionLocator; -import net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator; -import net.rubyeye.xmemcached.utils.AddrUtil; - -import com.googlecode.hibernate.memcached.Config; -import com.googlecode.hibernate.memcached.Memcache; -import com.googlecode.hibernate.memcached.MemcacheClientFactory; -import com.googlecode.hibernate.memcached.PropertiesHelper; - -/** - * Parses hibernate properties to produce a MemcachedClient.
- * See {@link com.googlecode.hibernate.memcached.MemcachedCacheProvider} for - * property details. SPI for xmemcached. - * - * @author dennis - */ -public class XmemcachedClientFactory implements MemcacheClientFactory { - - public static final String PROP_SERVERS = Config.PROP_PREFIX + "servers"; - public static final String PROP_READ_BUFFER_SIZE = Config.PROP_PREFIX - + "readBufferSize"; - public static final String PROP_OPERATION_TIMEOUT = Config.PROP_PREFIX - + "operationTimeout"; - public static final String PROP_HASH_ALGORITHM = Config.PROP_PREFIX - + "hashAlgorithm"; - public static final String PROP_COMMAND_FACTORY = Config.PROP_PREFIX - + "commandFactory"; - - public static final String PROP_SESSION_LOCATOR = Config.PROP_PREFIX - + "sessionLocator"; - - public static final String PROP_CONNECTION_POOL_SIZE = Config.PROP_PREFIX - + "connectionPoolSize"; - - public static final String PROP_CONNECT_TIMEOUT = Config.PROP_PREFIX - + "connectTimeout"; - - private final PropertiesHelper properties; - - public XmemcachedClientFactory(PropertiesHelper properties) { - this.properties = properties; - } - - public Memcache createMemcacheClient() throws Exception { - MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil - .getAddresses(getServerList())); - builder.setCommandFactory(getCommandFactory()); - builder.setSessionLocator(getSessionLocator()); - builder.getConfiguration() - .setSessionReadBufferSize(getReadBufferSize()); - builder.setConnectionPoolSize(getConnectionPoolSize()); - builder.setConnectTimeout(getConnectTimeoutMillis()); - MemcachedClient client = builder.build(); - client.setOpTimeout(getOperationTimeoutMillis()); - return new Xmemcache(client); - } - - protected MemcachedSessionLocator getSessionLocator() { - if (sessionLocatorNameEquals(ArrayMemcachedSessionLocator.class)) { - return new ArrayMemcachedSessionLocator(getHashAlgorithm()); - } - - if (sessionLocatorNameEquals(KetamaMemcachedSessionLocator.class)) { - return new KetamaMemcachedSessionLocator(getHashAlgorithm()); - } - - if (sessionLocatorNameEquals(PHPMemcacheSessionLocator.class)) { - return new PHPMemcacheSessionLocator(getHashAlgorithm()); - } - - throw new IllegalArgumentException("Unsupported " - + PROP_SESSION_LOCATOR + " value: " + getCommandFactoryName()); - } - - protected CommandFactory getCommandFactory() { - if (commandFactoryNameEquals(TextCommandFactory.class)) { - return new TextCommandFactory(); - } - - if (commandFactoryNameEquals(BinaryCommandFactory.class)) { - return new BinaryCommandFactory(); - } - - throw new IllegalArgumentException("Unsupported " - + PROP_COMMAND_FACTORY + " value: " + getCommandFactoryName()); - } - - private boolean commandFactoryNameEquals(Class cls) { - return cls.getSimpleName().equals(getCommandFactoryName()); - } - - private boolean sessionLocatorNameEquals(Class cls) { - return cls.getSimpleName().equals(getSessionLocatorName()); - } - - public String getServerList() { - return this.properties.get(PROP_SERVERS, "localhost:11211"); - } - - public int getReadBufferSize() { - return this.properties.getInt(PROP_READ_BUFFER_SIZE, - MemcachedClient.DEFAULT_SESSION_READ_BUFF_SIZE); - } - - - public int getConnectionPoolSize() { - return this.properties.getInt(PROP_CONNECTION_POOL_SIZE, - MemcachedClient.DEFAULT_CONNECTION_POOL_SIZE); - } - - public long getOperationTimeoutMillis() { - return this.properties.getLong(PROP_OPERATION_TIMEOUT, - MemcachedClient.DEFAULT_OP_TIMEOUT); - } - - public long getConnectTimeoutMillis() { - return this.properties.getLong(PROP_CONNECT_TIMEOUT, - MemcachedClient.DEFAULT_CONNECT_TIMEOUT); - } - - public HashAlgorithm getHashAlgorithm() { - return this.properties.getEnum(PROP_HASH_ALGORITHM, - HashAlgorithm.class, HashAlgorithm.NATIVE_HASH); - } - - public String getCommandFactoryName() { - return this.properties.get(PROP_COMMAND_FACTORY, - TextCommandFactory.class.getSimpleName()); - } - - public String getSessionLocatorName() { - return this.properties.get(PROP_SESSION_LOCATOR, - ArrayMemcachedSessionLocator.class.getSimpleName()); - } - - protected PropertiesHelper getProperties() { - return this.properties; - } -} diff --git a/src/main/java/net/rubyeye/xmemcached/utils/hibernate/package.html b/src/main/java/net/rubyeye/xmemcached/utils/hibernate/package.html deleted file mode 100644 index a63414b76..000000000 --- a/src/main/java/net/rubyeye/xmemcached/utils/hibernate/package.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - -Hibernate-memcached supports - - - -

Hibernate-memcached supports

- - - diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/hibernate/XmemcacheClientFactoryUnitIT.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/hibernate/XmemcacheClientFactoryUnitIT.java deleted file mode 100644 index f7cdc1e26..000000000 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/hibernate/XmemcacheClientFactoryUnitIT.java +++ /dev/null @@ -1,78 +0,0 @@ -package net.rubyeye.xmemcached.test.unittest.hibernate; - -import java.util.Map; -import java.util.Properties; - -import junit.framework.TestCase; -import net.rubyeye.xmemcached.utils.hibernate.XmemcachedClientFactory; - -import com.google.code.yanf4j.util.ResourcesUtils; -import com.googlecode.hibernate.memcached.Memcache; -import com.googlecode.hibernate.memcached.PropertiesHelper; -import com.googlecode.hibernate.memcached.spymemcached.SpyMemcacheClientFactory; - -public class XmemcacheClientFactoryUnitIT extends TestCase { - Properties properties; - - @Override - public void setUp() throws Exception { - Properties testProperties = ResourcesUtils - .getResourceAsProperties("test.properties"); - - this.properties = new Properties(); - this.properties.put(XmemcachedClientFactory.PROP_COMMAND_FACTORY, - "TextCommandFactory"); - this.properties.put(XmemcachedClientFactory.PROP_SESSION_LOCATOR, - "KetamaMemcachedSessionLocator"); - this.properties.put(XmemcachedClientFactory.PROP_HASH_ALGORITHM, - "CRC32_HASH"); - this.properties.put(XmemcachedClientFactory.PROP_OPERATION_TIMEOUT, - 2000); - this.properties.put(XmemcachedClientFactory.PROP_READ_BUFFER_SIZE, - 4 * 1024); - this.properties.put(XmemcachedClientFactory.PROP_SERVERS, - testProperties.get("test.memcached.servers")); - - } - - public void testXmemcachedClient() throws Exception { - PropertiesHelper propertiesHelper = new PropertiesHelper( - this.properties); - XmemcachedClientFactory clientFactory = new XmemcachedClientFactory( - propertiesHelper); - Memcache cache = clientFactory.createMemcacheClient(); - testCache(cache); - cache.shutdown(); - } - - private void testCache(Memcache cache) { - cache.set("a", 0, 1); - assertEquals(1, cache.get("a")); - cache.delete("a"); - assertNull(cache.get("a")); - cache.set("a", 0, 1); - cache.set("b", 0, 2); - - Map map = cache.getMulti("a", "b"); - assertEquals(2, map.size()); - assertEquals(1, map.get("a")); - assertEquals(2, map.get("b")); - - cache.incr("c", 1, 10); - assertEquals("10", cache.get("c")); - cache.incr("c", 1, 0); - assertEquals("11", cache.get("c")); - cache.delete("c"); - assertNull(cache.get("c")); - } - - public void testSpymemcacheClient() throws Exception { - PropertiesHelper propertiesHelper = new PropertiesHelper( - this.properties); - SpyMemcacheClientFactory clientFactory = new SpyMemcacheClientFactory( - propertiesHelper); - Memcache cache = clientFactory.createMemcacheClient(); - testCache(cache); - cache.shutdown(); - } -} From cdf3eaabb53b70fdc71f28e4ce7e35106afe6663 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Sat, 15 Oct 2016 18:08:58 +0800 Subject: [PATCH 077/207] (feat) Some helper classes for AWS ElastichCache auto discovery, #37 --- .../rubyeye/xmemcached/CommandFactory.java | 23 ++++- .../net/rubyeye/xmemcached/aws/AWSUtils.java | 62 +++++++++++++ .../net/rubyeye/xmemcached/aws/CacheNode.java | 50 +++++++++++ .../xmemcached/aws/ClusterConfigration.java | 55 ++++++++++++ .../xmemcached/aws/ConfigurationPoller.java | 51 +++++++++++ .../command/BinaryCommandFactory.java | 34 ++++--- .../xmemcached/command/CommandType.java | 6 +- .../command/KestrelCommandFactory.java | 13 ++- .../command/TextCommandFactory.java | 23 +++-- .../BinaryAWSElasticCacheConfigCommand.java | 88 +++++++++++++++++++ .../xmemcached/command/binary/OpCode.java | 23 +++++ .../TextAWSElasticCacheConfigCommand.java | 61 +++++++++++++ 12 files changed, 458 insertions(+), 31 deletions(-) create mode 100644 src/main/java/net/rubyeye/xmemcached/aws/AWSUtils.java create mode 100644 src/main/java/net/rubyeye/xmemcached/aws/CacheNode.java create mode 100644 src/main/java/net/rubyeye/xmemcached/aws/ClusterConfigration.java create mode 100644 src/main/java/net/rubyeye/xmemcached/aws/ConfigurationPoller.java create mode 100644 src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAWSElasticCacheConfigCommand.java create mode 100644 src/main/java/net/rubyeye/xmemcached/command/text/TextAWSElasticCacheConfigCommand.java diff --git a/src/main/java/net/rubyeye/xmemcached/CommandFactory.java b/src/main/java/net/rubyeye/xmemcached/CommandFactory.java index 8dc10c9f9..dc9440d52 100644 --- a/src/main/java/net/rubyeye/xmemcached/CommandFactory.java +++ b/src/main/java/net/rubyeye/xmemcached/CommandFactory.java @@ -267,7 +267,8 @@ public Command createAuthStepCommand(String mechanism, * @since 1.3.3 * @param key * @param keyBytes - * @param latch TODO + * @param latch + * TODO * @param exp * @param noreply * @return @@ -281,13 +282,29 @@ public Command createTouchCommand(final String key, final byte[] keyBytes, * @since 1.3.3 * @param key * @param keyBytes - * @param latch TODO + * @param latch + * TODO * @param exp * @param noreply * @return */ public Command createGetAndTouchCommand(final String key, - final byte[] keyBytes, CountDownLatch latch, int exp, boolean noreply); + final byte[] keyBytes, CountDownLatch latch, int exp, + boolean noreply); + + /** + * Create a AWS ElasticCache config command, only supports Cache Engine + * Version 1.4.14 or Higher. + * + * @see Adding + * Auto Discovery To Your Client Library + * @param subCommand + * @param key + * @return + */ + public Command createAWSElasticCacheConfigCommand(String subCommand, + String key); /** * Get this client's protocol version diff --git a/src/main/java/net/rubyeye/xmemcached/aws/AWSUtils.java b/src/main/java/net/rubyeye/xmemcached/aws/AWSUtils.java new file mode 100644 index 000000000..8bc3a6e87 --- /dev/null +++ b/src/main/java/net/rubyeye/xmemcached/aws/AWSUtils.java @@ -0,0 +1,62 @@ +package net.rubyeye.xmemcached.aws; + +import java.util.ArrayList; +import java.util.List; + +import net.rubyeye.xmemcached.utils.ByteUtils; + +/** + * AWS get config command + * + * @author dennis + * + */ +public class AWSUtils { + + private static final String DELIMITER = "|"; + + /** + * Parse response string to ClusterConfiguration instance. + * + * @param line + * @return + */ + public ClusterConfigration parseConfiguration(String line) { + String[] lines = line.trim().split("(?:\\r?\\n)"); + if (lines.length < 2) { + throw new IllegalArgumentException("Incorrect config response:" + + line); + } + String configversion = lines[0]; + String nodeListStr = lines[1]; + if (!ByteUtils.isNumber(configversion)) { + throw new IllegalArgumentException("Invalid configversion: " + + configversion + ", it should be a number."); + } + String[] nodeStrs = nodeListStr.split("(?:\\s)+"); + int version = Integer.parseInt(configversion); + List nodeList = new ArrayList(nodeStrs.length); + for (String nodeStr : nodeStrs) { + if (nodeStr.equals("")) { + continue; + } + + int firstDelimiter = nodeStr.indexOf(DELIMITER); + int secondDelimiter = nodeStr.lastIndexOf(DELIMITER); + if (firstDelimiter < 1 || firstDelimiter == secondDelimiter) { + throw new IllegalArgumentException("Invalid server ''" + + nodeStr + "'' in response: " + line); + } + String hostName = nodeStr.substring(0, firstDelimiter).trim(); + String ipAddress = nodeStr.substring(firstDelimiter + 1, + secondDelimiter).trim(); + String portNum = nodeStr.substring(secondDelimiter + 1).trim(); + int port = Integer.parseInt(portNum); + nodeList.add(new CacheNode(hostName, ipAddress, port)); + } + + return new ClusterConfigration(version, nodeList); + + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/aws/CacheNode.java b/src/main/java/net/rubyeye/xmemcached/aws/CacheNode.java new file mode 100644 index 000000000..876d0d0aa --- /dev/null +++ b/src/main/java/net/rubyeye/xmemcached/aws/CacheNode.java @@ -0,0 +1,50 @@ +package net.rubyeye.xmemcached.aws; + +import java.io.Serializable; + +/** + * AWS ElasticCache Node information. + * + * @author dennis + * + */ +public class CacheNode implements Serializable { + + private static final long serialVersionUID = -2999058612548153786L; + + public String getHostName() { + return hostName; + } + + public void setHostName(String hostName) { + this.hostName = hostName; + } + + public String getIpAddress() { + return ipAddress; + } + + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + private String hostName; + private String ipAddress; + private int port; + + public CacheNode(String hostName, String ipAddress, int port) { + super(); + this.hostName = hostName; + this.ipAddress = ipAddress; + this.port = port; + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/aws/ClusterConfigration.java b/src/main/java/net/rubyeye/xmemcached/aws/ClusterConfigration.java new file mode 100644 index 000000000..583eb42f9 --- /dev/null +++ b/src/main/java/net/rubyeye/xmemcached/aws/ClusterConfigration.java @@ -0,0 +1,55 @@ +package net.rubyeye.xmemcached.aws; + +import java.io.Serializable; +import java.util.List; + +/** + * Cluster configuration retrieved from ElasticCache. + * + * @author dennis + * + */ +public class ClusterConfigration implements Serializable { + + private static final long serialVersionUID = 6809891639636689050L; + + public int getVersion() { + return version; + } + + public void setVersion(int version) { + this.version = version; + } + + public List getNodeList() { + return nodeList; + } + + public void setNodeList(List nodeList) { + this.nodeList = nodeList; + } + + private int version; + private List nodeList; + + public ClusterConfigration(int version, List nodeList) { + super(); + this.version = version; + this.nodeList = nodeList; + } + + public ClusterConfigration() { + super(); + } + + + public String toString() { + StringBuilder nodeList = new StringBuilder("Version:" + version + + " CacheNode List:"); + for (CacheNode node : this.nodeList) { + nodeList.append(" " + node.getHostName() + ":" + node.getPort()); + } + + return nodeList.toString(); + } +} diff --git a/src/main/java/net/rubyeye/xmemcached/aws/ConfigurationPoller.java b/src/main/java/net/rubyeye/xmemcached/aws/ConfigurationPoller.java new file mode 100644 index 000000000..a3a53f895 --- /dev/null +++ b/src/main/java/net/rubyeye/xmemcached/aws/ConfigurationPoller.java @@ -0,0 +1,51 @@ +package net.rubyeye.xmemcached.aws; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import net.rubyeye.xmemcached.MemcachedClient; + +/** + * AWS ElastiCache configuration poller + * + * @author dennis + * + */ +public class ConfigurationPoller implements Runnable { + + /** + * Return current ElasticCache node list. + * + * @return + */ + public List getCurrentNodeList() { + return currentNodeList; + } + + private MemcachedClient client; + + private int pollIntervalMills; + + private ScheduledExecutorService scheduledExecutorService; + + private volatile List currentNodeList = Collections.emptyList(); + + public ConfigurationPoller(MemcachedClient client, int pollIntervalMills) { + super(); + this.client = client; + this.pollIntervalMills = pollIntervalMills; + this.scheduledExecutorService = Executors + .newSingleThreadScheduledExecutor(); + this.scheduledExecutorService.scheduleWithFixedDelay(this, + this.pollIntervalMills, this.pollIntervalMills, + TimeUnit.MILLISECONDS); + } + + public void run() { + + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/command/BinaryCommandFactory.java b/src/main/java/net/rubyeye/xmemcached/command/BinaryCommandFactory.java index fdc39c8a1..7046c2fed 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/BinaryCommandFactory.java +++ b/src/main/java/net/rubyeye/xmemcached/command/BinaryCommandFactory.java @@ -10,6 +10,7 @@ import net.rubyeye.xmemcached.CommandFactory; import net.rubyeye.xmemcached.buffer.BufferAllocator; import net.rubyeye.xmemcached.buffer.SimpleBufferAllocator; +import net.rubyeye.xmemcached.command.binary.BinaryAWSElasticCacheConfigCommand; import net.rubyeye.xmemcached.command.binary.BinaryAppendPrependCommand; import net.rubyeye.xmemcached.command.binary.BinaryAuthListMechanismsCommand; import net.rubyeye.xmemcached.command.binary.BinaryAuthStartCommand; @@ -43,6 +44,12 @@ @SuppressWarnings("unchecked") public class BinaryCommandFactory implements CommandFactory { + public Command createAWSElasticCacheConfigCommand(String subCommand, + String key) { + return new BinaryAWSElasticCacheConfigCommand(new CountDownLatch(1), + subCommand, key); + } + private BufferAllocator bufferAllocator = new SimpleBufferAllocator(); public void setBufferAllocator(BufferAllocator bufferAllocator) { @@ -51,8 +58,8 @@ public void setBufferAllocator(BufferAllocator bufferAllocator) { public Command createAddCommand(String key, byte[] keyBytes, int exp, Object value, boolean noreply, Transcoder transcoder) { - return this.createStoreCommand(key, keyBytes, exp, value, CommandType.ADD, - noreply, transcoder); + return this.createStoreCommand(key, keyBytes, exp, value, + CommandType.ADD, noreply, transcoder); } public Command createAppendCommand(String key, byte[] keyBytes, @@ -69,8 +76,7 @@ public Command createCASCommand(String key, byte[] keyBytes, int exp, } public Command createDeleteCommand(String key, byte[] keyBytes, int time, - long cas, - boolean noreply) { + long cas, boolean noreply) { return new BinaryDeleteCommand(key, keyBytes, cas, CommandType.DELETE, new CountDownLatch(1), noreply); } @@ -96,9 +102,9 @@ public Command createGetMultiCommand(Collection keys, key = it.next(); if (it.hasNext()) { // first n-1 send getq command - Command command = new BinaryGetCommand(key, ByteUtils - .getBytes(key), cmdType, null, OpCode.GET_KEY_QUIETLY, - true); + Command command = new BinaryGetCommand(key, + ByteUtils.getBytes(key), cmdType, null, + OpCode.GET_KEY_QUIETLY, true); command.encode(); totalLength += command.getIoBuffer().remaining(); bufferList.add(command.getIoBuffer()); @@ -151,8 +157,8 @@ final Command createStoreCommand(String key, byte[] keyBytes, int exp, public Command createSetCommand(String key, byte[] keyBytes, int exp, Object value, boolean noreply, Transcoder transcoder) { - return this.createStoreCommand(key, keyBytes, exp, value, CommandType.SET, - noreply, transcoder); + return this.createStoreCommand(key, keyBytes, exp, value, + CommandType.SET, noreply, transcoder); } public Command createStatsCommand(InetSocketAddress server, @@ -176,21 +182,21 @@ public Command createAuthListMechanismsCommand(CountDownLatch latch) { public Command createAuthStartCommand(String mechanism, CountDownLatch latch, byte[] authData) { - return new BinaryAuthStartCommand(mechanism, ByteUtils - .getBytes(mechanism), latch, authData); + return new BinaryAuthStartCommand(mechanism, + ByteUtils.getBytes(mechanism), latch, authData); } public Command createAuthStepCommand(String mechanism, CountDownLatch latch, byte[] authData) { - return new BinaryAuthStepCommand(mechanism, ByteUtils - .getBytes(mechanism), latch, authData); + return new BinaryAuthStepCommand(mechanism, + ByteUtils.getBytes(mechanism), latch, authData); } public Command createGetAndTouchCommand(String key, byte[] keyBytes, CountDownLatch latch, int exp, boolean noreply) { return new BinaryGetAndTouchCommand(key, keyBytes, noreply ? CommandType.GATQ : CommandType.GAT, latch, exp, - noreply); + noreply); } public Command createTouchCommand(String key, byte[] keyBytes, diff --git a/src/main/java/net/rubyeye/xmemcached/command/CommandType.java b/src/main/java/net/rubyeye/xmemcached/command/CommandType.java index 73237280e..632728bf0 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/CommandType.java +++ b/src/main/java/net/rubyeye/xmemcached/command/CommandType.java @@ -8,6 +8,8 @@ */ public enum CommandType { - NOOP, STATS, FLUSH_ALL, GET_ONE, GET_MANY, SET, REPLACE, ADD, EXCEPTION, DELETE, VERSION, QUIT, INCR, DECR, GETS_ONE, GETS_MANY, CAS, APPEND, PREPEND, GET_HIT, GET_MISS, VERBOSITY, AUTH_LIST, AUTH_START, AUTH_STEP, TOUCH, GAT, GATQ, SET_MANY; - + NOOP, STATS, FLUSH_ALL, GET_ONE, GET_MANY, SET, REPLACE, ADD, EXCEPTION, // + DELETE, VERSION, QUIT, INCR, DECR, GETS_ONE, GETS_MANY, CAS, APPEND, PREPEND, // + GET_HIT, GET_MISS, VERBOSITY, AUTH_LIST, AUTH_START, AUTH_STEP, TOUCH, GAT, GATQ, SET_MANY, // + AWS_CONFIG; } \ No newline at end of file diff --git a/src/main/java/net/rubyeye/xmemcached/command/KestrelCommandFactory.java b/src/main/java/net/rubyeye/xmemcached/command/KestrelCommandFactory.java index 3ca6b86f6..20a44c153 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/KestrelCommandFactory.java +++ b/src/main/java/net/rubyeye/xmemcached/command/KestrelCommandFactory.java @@ -28,6 +28,12 @@ @SuppressWarnings("unchecked") public class KestrelCommandFactory implements CommandFactory { + public Command createAWSElasticCacheConfigCommand(String subCommand, + String key) { + throw new UnsupportedOperationException( + "Kestrel doesn't support this operation"); + } + public Command createAddCommand(String key, byte[] keyBytes, int exp, Object value, boolean noreply, Transcoder transcoder) { throw new UnsupportedOperationException( @@ -47,8 +53,7 @@ public Command createCASCommand(String key, byte[] keyBytes, int exp, } public Command createDeleteCommand(String key, byte[] keyBytes, int time, - long cas, - boolean noreply) { + long cas, boolean noreply) { return new KestrelDeleteCommand(key, keyBytes, -1, new CountDownLatch(1), noreply); } @@ -144,8 +149,8 @@ public Command createGetAndTouchCommand(String key, byte[] keyBytes, "GAT is only supported by binary protocol"); } - public Command createTouchCommand(String key, byte[] keyBytes, CountDownLatch latch, - int exp, boolean noreply) { + public Command createTouchCommand(String key, byte[] keyBytes, + CountDownLatch latch, int exp, boolean noreply) { throw new UnsupportedOperationException( "Touch is only supported by binary protocol"); } diff --git a/src/main/java/net/rubyeye/xmemcached/command/TextCommandFactory.java b/src/main/java/net/rubyeye/xmemcached/command/TextCommandFactory.java index 216ba4303..2f4c74030 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/TextCommandFactory.java +++ b/src/main/java/net/rubyeye/xmemcached/command/TextCommandFactory.java @@ -6,6 +6,7 @@ import net.rubyeye.xmemcached.CommandFactory; import net.rubyeye.xmemcached.buffer.BufferAllocator; +import net.rubyeye.xmemcached.command.text.TextAWSElasticCacheConfigCommand; import net.rubyeye.xmemcached.command.text.TextCASCommand; import net.rubyeye.xmemcached.command.text.TextDeleteCommand; import net.rubyeye.xmemcached.command.text.TextFlushAllCommand; @@ -30,6 +31,12 @@ */ public class TextCommandFactory implements CommandFactory { + public Command createAWSElasticCacheConfigCommand(String subCommand, + String key) { + return new TextAWSElasticCacheConfigCommand(new CountDownLatch(1), + subCommand, key); + } + public void setBufferAllocator(BufferAllocator bufferAllocator) { } @@ -114,16 +121,16 @@ public final Command createCASCommand(final String key, public final Command createSetCommand(final String key, final byte[] keyBytes, final int exp, final Object value, boolean noreply, Transcoder transcoder) { - return this.createStoreCommand(key, keyBytes, exp, value, CommandType.SET, - noreply, transcoder); + return this.createStoreCommand(key, keyBytes, exp, value, + CommandType.SET, noreply, transcoder); } @SuppressWarnings("unchecked") public final Command createAddCommand(final String key, final byte[] keyBytes, final int exp, final Object value, boolean noreply, Transcoder transcoder) { - return this.createStoreCommand(key, keyBytes, exp, value, CommandType.ADD, - noreply, transcoder); + return this.createStoreCommand(key, keyBytes, exp, value, + CommandType.ADD, noreply, transcoder); } @SuppressWarnings("unchecked") @@ -138,16 +145,16 @@ public final Command createReplaceCommand(final String key, public final Command createAppendCommand(final String key, final byte[] keyBytes, final Object value, boolean noreply, Transcoder transcoder) { - return this.createStoreCommand(key, keyBytes, 0, value, CommandType.APPEND, - noreply, transcoder); + return this.createStoreCommand(key, keyBytes, 0, value, + CommandType.APPEND, noreply, transcoder); } @SuppressWarnings("unchecked") public final Command createPrependCommand(final String key, final byte[] keyBytes, final Object value, boolean noreply, Transcoder transcoder) { - return this.createStoreCommand(key, keyBytes, 0, value, CommandType.PREPEND, - noreply, transcoder); + return this.createStoreCommand(key, keyBytes, 0, value, + CommandType.PREPEND, noreply, transcoder); } @SuppressWarnings("unchecked") diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAWSElasticCacheConfigCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAWSElasticCacheConfigCommand.java new file mode 100644 index 000000000..7b3e03369 --- /dev/null +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAWSElasticCacheConfigCommand.java @@ -0,0 +1,88 @@ +/** + *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] + *Licensed 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 + */ +/** + *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] + *Licensed 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 net.rubyeye.xmemcached.command.binary; + +import java.nio.ByteBuffer; +import java.util.concurrent.CountDownLatch; + +import net.rubyeye.xmemcached.command.CommandType; +import net.rubyeye.xmemcached.transcoders.CachedData; +import net.rubyeye.xmemcached.utils.ByteUtils; + +/** + * AWS ElasticCache config command + * + * @author dennis + * + */ +public class BinaryAWSElasticCacheConfigCommand extends BaseBinaryCommand { + + public BinaryAWSElasticCacheConfigCommand(final CountDownLatch latch, + String subCommand, String key) { + super(key, ByteUtils.getBytes(key), CommandType.AWS_CONFIG, latch, 0, + 0, latch, false, null); + this.commandType = CommandType.AWS_CONFIG; + if (subCommand.equals("get")) { + this.opCode = OpCode.CONFIG_GET; + } else if (subCommand.equals("set")) { + this.opCode = OpCode.CONFIG_SET; + } else if (subCommand.equals("delete")) { + this.opCode = OpCode.CONFIG_DEL; + } + } + + @Override + protected boolean readValue(ByteBuffer buffer, int bodyLength, + int keyLength, int extrasLength) { + int valueLength = bodyLength - keyLength - extrasLength; + if (buffer.remaining() < valueLength) { + return false; + } + byte[] bytes = new byte[valueLength]; + buffer.get(bytes); + setResult(new String(bytes)); + countDownLatch(); + return true; + } + + @Override + protected void fillExtras(CachedData data) { + // must not have extras + } + + @Override + protected void fillValue(CachedData data) { + // must not have value + } + + @Override + protected byte getExtrasLength() { + return 0; + } + + @Override + protected int getValueLength(CachedData data) { + return 0; + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/OpCode.java b/src/main/java/net/rubyeye/xmemcached/command/binary/OpCode.java index f57f14674..9aa05e461 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/OpCode.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/OpCode.java @@ -260,6 +260,29 @@ public byte fieldValue() { public byte fieldValue() { return 0x1e; + } + }, + // AWS ElasticCache config commands + // https://github.com/awslabs/aws-elasticache-cluster-client-memcached-for-java/commit/70bf7643963500db20749d97c071b64b954eabb3 + CONFIG_GET { + @Override + public byte fieldValue() { + return 0x60; + + } + }, + CONFIG_SET { + @Override + public byte fieldValue() { + return 0x64; + + } + }, + CONFIG_DEL { + @Override + public byte fieldValue() { + return 0x66; + } }; diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextAWSElasticCacheConfigCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextAWSElasticCacheConfigCommand.java new file mode 100644 index 000000000..f2e7f5695 --- /dev/null +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextAWSElasticCacheConfigCommand.java @@ -0,0 +1,61 @@ +package net.rubyeye.xmemcached.command.text; + +import java.nio.ByteBuffer; +import java.util.concurrent.CountDownLatch; + +import com.google.code.yanf4j.buffer.IoBuffer; + +import net.rubyeye.xmemcached.aws.AWSUtils; +import net.rubyeye.xmemcached.command.Command; +import net.rubyeye.xmemcached.command.CommandType; +import net.rubyeye.xmemcached.impl.MemcachedTCPSession; +import net.rubyeye.xmemcached.utils.ByteUtils; + +/** + * AWS ElasticCache config command, see Adding Auto Discovery To Your Client Library. Only supports Cache Engine + * version 1.4.14 or higher. + * + * @author dennis + * + */ +public class TextAWSElasticCacheConfigCommand extends Command { + + private String key; + + private String subCommand; + + public TextAWSElasticCacheConfigCommand(final CountDownLatch latch, + String subCommand, String key) { + super(CommandType.AWS_CONFIG, latch); + this.key = key; + this.subCommand = subCommand; + } + + @Override + public boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { + if (buffer == null || !buffer.hasRemaining()) { + return false; + } + String line = ByteUtils.nextLine(buffer); + if (line != null) { + setResult(line); + return true; + } else { + return false; + } + } + + @Override + public void encode() { + // config [sub-command] [key] + final byte[] subCmdBytes = ByteUtils.getBytes(this.subCommand); + final byte[] keyBytes = ByteUtils.getBytes(this.key); + this.ioBuffer = IoBuffer.allocate(5 + 1 + subCmdBytes.length + 1 + + +keyBytes.length); + ByteUtils.setArguments(this.ioBuffer, "config", subCmdBytes, keyBytes); + this.ioBuffer.flip(); + } + +} From ff0afda14604d477f2120aea1e412e655b2d402e Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Sat, 15 Oct 2016 19:22:25 +0800 Subject: [PATCH 078/207] (feat) Adds AWSElasticCacheClient and ConfigUpdateListener --- .../rubyeye/xmemcached/XMemcachedClient.java | 8 +- .../xmemcached/aws/AWSElasticCacheClient.java | 86 +++++++++++++++++++ .../net/rubyeye/xmemcached/aws/AWSUtils.java | 2 +- .../xmemcached/aws/ConfigUpdateListener.java | 18 ++++ .../xmemcached/aws/ConfigurationPoller.java | 71 ++++++++++++--- 5 files changed, 167 insertions(+), 18 deletions(-) create mode 100644 src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java create mode 100644 src/main/java/net/rubyeye/xmemcached/aws/ConfigUpdateListener.java diff --git a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java index 78cf11d18..0f31dafe3 100644 --- a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java +++ b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java @@ -93,7 +93,7 @@ public class XMemcachedClient implements XMemcachedClientMBean, MemcachedClient private boolean sanitizeKeys; private MemcachedHandler memcachedHandler; protected CommandFactory commandFactory; - private long opTimeout = DEFAULT_OP_TIMEOUT; + protected long opTimeout = DEFAULT_OP_TIMEOUT; private long connectTimeout = DEFAULT_CONNECT_TIMEOUT; protected int connectionPoolSize = DEFAULT_CONNECTION_POOL_SIZE; protected int maxQueuedNoReplyOperations = DEFAULT_MAX_QUEUED_NOPS; @@ -319,7 +319,7 @@ private final GetsResponse gets0(final String key, return result; } - private final Session sendCommand(final Command cmd) + protected final Session sendCommand(final Command cmd) throws MemcachedException { if (this.shutdown) { throw new MemcachedException("Xmemcached is stopped"); @@ -1926,7 +1926,7 @@ private boolean delete0(String key, final int time, long cas, return (Boolean) command.getResult(); } - void checkException(final Command command) throws MemcachedException { + protected void checkException(final Command command) throws MemcachedException { if (command.getException() != null) { if (command.getException() instanceof MemcachedException) { throw (MemcachedException) command.getException(); @@ -2523,7 +2523,7 @@ private final boolean sendStoreCommand(Command command, long timeout) private static final String CONTINUOUS_TIMEOUT_COUNTER = "ContinuousTimeouts"; - private void latchWait(final Command cmd, final long timeout, + protected void latchWait(final Command cmd, final long timeout, final Session session) throws InterruptedException, TimeoutException { if (cmd.getLatch().await(timeout, TimeUnit.MILLISECONDS)) { diff --git a/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java b/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java new file mode 100644 index 000000000..98b00d81b --- /dev/null +++ b/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java @@ -0,0 +1,86 @@ +package net.rubyeye.xmemcached.aws; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.concurrent.TimeoutException; + +import com.google.code.yanf4j.core.Session; + +import net.rubyeye.xmemcached.XMemcachedClient; +import net.rubyeye.xmemcached.command.Command; +import net.rubyeye.xmemcached.exception.MemcachedException; + +/** + * AWS ElasticCache Client. + * + * @author dennis + * + */ +public class AWSElasticCacheClient extends XMemcachedClient implements + ConfigUpdateListener { + + public void onUpdate(ClusterConfigration config) { + this.currentClusterConfiguration = config; + // TODO update with new node list + } + + private final ConfigurationPoller configPoller; + + public AWSElasticCacheClient(InetSocketAddress addr, + long pollConfigIntervalMills) throws IOException { + super(addr); + this.configPoller = new ConfigurationPoller(this, + pollConfigIntervalMills); + // Run at once to get config at startup. + // It will call onUpdate in the same thread. + this.configPoller.run(); + if (this.currentClusterConfiguration == null) { + throw new IllegalStateException( + "Retrieve ElasticCache config from `" + addr.toString() + + "` failed."); + } + this.configPoller.start(); + } + + private volatile ClusterConfigration currentClusterConfiguration; + + /** + * Get cluster config from cache node by network command. + * + * @return + */ + public ClusterConfigration getConfig() throws MemcachedException, + InterruptedException, TimeoutException { + return this.getConfig("cluster"); + } + + /** + * Get config by key from cache node by network command. + * + * @return + */ + public ClusterConfigration getConfig(String key) throws MemcachedException, + InterruptedException, TimeoutException { + Command cmd = this.commandFactory.createAWSElasticCacheConfigCommand( + "get", key); + final Session session = this.sendCommand(cmd); + this.latchWait(cmd, opTimeout, session); + cmd.getIoBuffer().free(); + this.checkException(cmd); + String result = (String) cmd.getResult(); + if (result == null) { + throw new MemcachedException( + "Operation fail,may be caused by networking or timeout"); + } + return AWSUtils.parseConfiguration(result); + } + + /** + * Get the current using configuration in memory. + * + * @return + */ + public ClusterConfigration getCurrentConfig() { + return this.currentClusterConfiguration; + } +} diff --git a/src/main/java/net/rubyeye/xmemcached/aws/AWSUtils.java b/src/main/java/net/rubyeye/xmemcached/aws/AWSUtils.java index 8bc3a6e87..a82b26484 100644 --- a/src/main/java/net/rubyeye/xmemcached/aws/AWSUtils.java +++ b/src/main/java/net/rubyeye/xmemcached/aws/AWSUtils.java @@ -21,7 +21,7 @@ public class AWSUtils { * @param line * @return */ - public ClusterConfigration parseConfiguration(String line) { + public static ClusterConfigration parseConfiguration(String line) { String[] lines = line.trim().split("(?:\\r?\\n)"); if (lines.length < 2) { throw new IllegalArgumentException("Incorrect config response:" diff --git a/src/main/java/net/rubyeye/xmemcached/aws/ConfigUpdateListener.java b/src/main/java/net/rubyeye/xmemcached/aws/ConfigUpdateListener.java new file mode 100644 index 000000000..9fbeeb07e --- /dev/null +++ b/src/main/java/net/rubyeye/xmemcached/aws/ConfigUpdateListener.java @@ -0,0 +1,18 @@ +package net.rubyeye.xmemcached.aws; + +/** + * AWS ElasticCache config update event listener. + * + * @author dennis + * + */ +public interface ConfigUpdateListener { + + /** + * Called when config is changed. + * + * @param config + * the new config + */ + public void onUpdate(ClusterConfigration config); +} diff --git a/src/main/java/net/rubyeye/xmemcached/aws/ConfigurationPoller.java b/src/main/java/net/rubyeye/xmemcached/aws/ConfigurationPoller.java index a3a53f895..53137eb37 100644 --- a/src/main/java/net/rubyeye/xmemcached/aws/ConfigurationPoller.java +++ b/src/main/java/net/rubyeye/xmemcached/aws/ConfigurationPoller.java @@ -1,12 +1,12 @@ package net.rubyeye.xmemcached.aws; -import java.util.Collections; -import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; -import net.rubyeye.xmemcached.MemcachedClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * AWS ElastiCache configuration poller @@ -17,35 +17,80 @@ public class ConfigurationPoller implements Runnable { /** - * Return current ElasticCache node list. + * Return current ClusterConfigration. * * @return */ - public List getCurrentNodeList() { - return currentNodeList; + public ClusterConfigration getClusterConfiguration() { + return clusterConfigration; } - private MemcachedClient client; + private static final Logger log = LoggerFactory + .getLogger(ConfigurationPoller.class); - private int pollIntervalMills; + private final AWSElasticCacheClient client; + + private final long pollIntervalMills; private ScheduledExecutorService scheduledExecutorService; - private volatile List currentNodeList = Collections.emptyList(); + private volatile ClusterConfigration clusterConfigration = null; - public ConfigurationPoller(MemcachedClient client, int pollIntervalMills) { + public ConfigurationPoller(AWSElasticCacheClient client, + long pollIntervalMills) { super(); this.client = client; this.pollIntervalMills = pollIntervalMills; this.scheduledExecutorService = Executors - .newSingleThreadScheduledExecutor(); + .newSingleThreadScheduledExecutor(new ThreadFactory() { + + public Thread newThread(Runnable r) { + Thread t = new Thread(r, "AWSElasticCacheConfigPoller"); + t.setDaemon(true); + if (t.getPriority() != Thread.NORM_PRIORITY) { + t.setPriority(Thread.NORM_PRIORITY); + } + return t; + } + }); + } + + public void start() { this.scheduledExecutorService.scheduleWithFixedDelay(this, this.pollIntervalMills, this.pollIntervalMills, TimeUnit.MILLISECONDS); } - public void run() { - + public void stop() { + this.scheduledExecutorService.shutdown(); } + public void run() { + try { + ClusterConfigration newConfig = this.client.getConfig(); + if (newConfig != null) { + ClusterConfigration currentConfig = this.clusterConfigration; + if (currentConfig == null) { + this.clusterConfigration = newConfig; + } else { + if (newConfig.getVersion() < currentConfig.getVersion()) { + log.warn("Ignored new config from ElasticCache node, it's too old, current version is: " + + currentConfig.getVersion() + + ", but the new version is: " + + newConfig.getVersion()); + return; + } else { + this.clusterConfigration = newConfig; + } + } + log.info("Retrieved new config from ElasticCache node: " + + this.clusterConfigration); + this.client.onUpdate(newConfig); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } catch (Exception e) { + log.error("Poll config from ElasticCache node failed", e); + } + } } From eeb900b956c14859a59af6ac858cbb27ca83f769 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Fri, 21 Oct 2016 12:17:43 +0800 Subject: [PATCH 079/207] (feat) Update servers when configuration is changed. --- .../rubyeye/xmemcached/XMemcachedClient.java | 69 +++++++++--------- .../xmemcached/aws/AWSElasticCacheClient.java | 72 ++++++++++++++++++- .../net/rubyeye/xmemcached/aws/CacheNode.java | 47 ++++++++++++ .../xmemcached/aws/ConfigurationPoller.java | 21 ++++++ .../rubyeye/xmemcached/utils/ByteUtils.java | 4 ++ .../utils/InetSocketAddressWrapper.java | 8 +-- 6 files changed, 178 insertions(+), 43 deletions(-) diff --git a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java index 0f31dafe3..e5da577fc 100644 --- a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java +++ b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java @@ -534,53 +534,52 @@ public final void removeServer(String hostList) { List addresses = AddrUtil.getAddresses(hostList); if (addresses != null && addresses.size() > 0) { for (InetSocketAddress address : addresses) { - // Close main sessions - Queue sessionQueue = this.connector - .getSessionByAddress(address); - if (sessionQueue != null) { - for (Session session : sessionQueue) { - if (session != null) { - // Disable auto reconnection - ((MemcachedSession) session) - .setAllowReconnect(false); - // Close connection - ((MemcachedSession) session).quit(); - } - } - } - // Close standby sessions - List standBySession = this.connector - .getStandbySessionListByMainNodeAddr(address); - if (standBySession != null) { - for (Session session : standBySession) { - if (session != null) { - this.connector.removeReconnectRequest(session - .getRemoteSocketAddress()); - // Disable auto reconnection - ((MemcachedSession) session) - .setAllowReconnect(false); - // Close connection - ((MemcachedSession) session).quit(); - } - } - } - this.connector.removeReconnectRequest(address); + removeAddr(address); } } } - protected void checkSocketAddress(InetSocketAddress address) { - + protected void removeAddr(InetSocketAddress address) { + // Close main sessions + Queue sessionQueue = this.connector + .getSessionByAddress(address); + if (sessionQueue != null) { + for (Session session : sessionQueue) { + if (session != null) { + // Disable auto reconnection + ((MemcachedSession) session) + .setAllowReconnect(false); + // Close connection + ((MemcachedSession) session).quit(); + } + } + } + // Close standby sessions + List standBySession = this.connector + .getStandbySessionListByMainNodeAddr(address); + if (standBySession != null) { + for (Session session : standBySession) { + if (session != null) { + this.connector.removeReconnectRequest(session + .getRemoteSocketAddress()); + // Disable auto reconnection + ((MemcachedSession) session) + .setAllowReconnect(false); + // Close connection + ((MemcachedSession) session).quit(); + } + } + } + this.connector.removeReconnectRequest(address); } - private void connect(final InetSocketAddressWrapper inetSocketAddressWrapper) + protected void connect(final InetSocketAddressWrapper inetSocketAddressWrapper) throws IOException { // creat connection pool InetSocketAddress inetSocketAddress = inetSocketAddressWrapper .getInetSocketAddress(); - this.checkSocketAddress(inetSocketAddress); if (this.connectionPoolSize > 1) { log.warn("You are using connection pool for xmemcached client,it's not recommended unless you have test it that it can boost performance in your app."); } diff --git a/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java b/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java index 98b00d81b..8bedd8399 100644 --- a/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java +++ b/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java @@ -2,13 +2,20 @@ import java.io.IOException; import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.concurrent.TimeoutException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.google.code.yanf4j.core.Session; import net.rubyeye.xmemcached.XMemcachedClient; import net.rubyeye.xmemcached.command.Command; import net.rubyeye.xmemcached.exception.MemcachedException; +import net.rubyeye.xmemcached.utils.InetSocketAddressWrapper; /** * AWS ElasticCache Client. @@ -19,9 +26,67 @@ public class AWSElasticCacheClient extends XMemcachedClient implements ConfigUpdateListener { - public void onUpdate(ClusterConfigration config) { + private static final Logger log = LoggerFactory + .getLogger(AWSElasticCacheClient.class); + + private boolean firstTimeUpdate = true; + + private InetSocketAddress configAddr; + + public synchronized void onUpdate(ClusterConfigration config) { + + if (firstTimeUpdate) { + firstTimeUpdate = false; + removeConfigAddr(); + } + + List oldList = this.currentClusterConfiguration != null ? this.currentClusterConfiguration + .getNodeList() : Collections.EMPTY_LIST; + List newList = config.getNodeList(); + + List addNodes = new ArrayList(); + List removeNodes = new ArrayList(); + + for (CacheNode node : newList) { + if (!oldList.contains(node)) { + addNodes.add(node); + } + } + + for (CacheNode node : oldList) { + if (!newList.contains(node)) { + removeNodes.add(node); + } + } + + // Begin to update server list + for (CacheNode node : addNodes) { + try { + this.connect(new InetSocketAddressWrapper(node + .getInetSocketAddress(), this.configPoller + .getCacheNodeOrder(node), 1, null)); + } catch (IOException e) { + log.error("Connect to " + node + "failed.", e); + } + } + + for (CacheNode node : removeNodes) { + this.removeAddr(node.getInetSocketAddress()); + } + this.currentClusterConfiguration = config; - // TODO update with new node list + } + + private void removeConfigAddr() { + this.removeAddr(configAddr); + while (this.getConnector().getSessionByAddress(configAddr) != null + && this.getConnector().getSessionByAddress(configAddr).size() > 0) { + try { + Thread.sleep(50); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } } private final ConfigurationPoller configPoller; @@ -29,6 +94,9 @@ public void onUpdate(ClusterConfigration config) { public AWSElasticCacheClient(InetSocketAddress addr, long pollConfigIntervalMills) throws IOException { super(addr); + // Use failure mode by default. + this.setFailureMode(true); + this.configAddr = addr; this.configPoller = new ConfigurationPoller(this, pollConfigIntervalMills); // Run at once to get config at startup. diff --git a/src/main/java/net/rubyeye/xmemcached/aws/CacheNode.java b/src/main/java/net/rubyeye/xmemcached/aws/CacheNode.java index 876d0d0aa..4688edcc8 100644 --- a/src/main/java/net/rubyeye/xmemcached/aws/CacheNode.java +++ b/src/main/java/net/rubyeye/xmemcached/aws/CacheNode.java @@ -1,6 +1,11 @@ package net.rubyeye.xmemcached.aws; import java.io.Serializable; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; + +import net.rubyeye.xmemcached.utils.ByteUtils; /** * AWS ElasticCache Node information. @@ -10,6 +15,35 @@ */ public class CacheNode implements Serializable { + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((hostName == null) ? 0 : hostName.hashCode()); + result = prime * result + port; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + CacheNode other = (CacheNode) obj; + if (hostName == null) { + if (other.hostName != null) + return false; + } else if (!hostName.equals(other.hostName)) + return false; + if (port != other.port) + return false; + return true; + } + private static final long serialVersionUID = -2999058612548153786L; public String getHostName() { @@ -20,6 +54,10 @@ public void setHostName(String hostName) { this.hostName = hostName; } + public InetSocketAddress getInetSocketAddress() { + return new InetSocketAddress(hostName, port); + } + public String getIpAddress() { return ipAddress; } @@ -36,6 +74,15 @@ public void setPort(int port) { this.port = port; } + public String toString() { + return "[" + this.hostName + "|" + this.ipAddress + "|" + this.port + + "]"; + } + + public String getCacheKey() { + return this.hostName + ":" + this.port; + } + private String hostName; private String ipAddress; private int port; diff --git a/src/main/java/net/rubyeye/xmemcached/aws/ConfigurationPoller.java b/src/main/java/net/rubyeye/xmemcached/aws/ConfigurationPoller.java index 53137eb37..31538b552 100644 --- a/src/main/java/net/rubyeye/xmemcached/aws/ConfigurationPoller.java +++ b/src/main/java/net/rubyeye/xmemcached/aws/ConfigurationPoller.java @@ -1,9 +1,12 @@ package net.rubyeye.xmemcached.aws; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,6 +28,24 @@ public ClusterConfigration getClusterConfiguration() { return clusterConfigration; } + private final AtomicInteger serverOrderCounter = new AtomicInteger(0); + + private Map ordersMap = new HashMap(); + + public synchronized int getCacheNodeOrder(CacheNode node) { + Integer order = this.ordersMap.get(node.getCacheKey()); + if (order != null) { + return order; + } + order = this.serverOrderCounter.incrementAndGet(); + this.ordersMap.put(node.getCacheKey(), order); + return order; + } + + public synchronized void removeCacheNodeOrder(CacheNode node) { + this.ordersMap.remove(node.getCacheKey()); + } + private static final Logger log = LoggerFactory .getLogger(ConfigurationPoller.class); diff --git a/src/main/java/net/rubyeye/xmemcached/utils/ByteUtils.java b/src/main/java/net/rubyeye/xmemcached/utils/ByteUtils.java index 56f935fab..f5b8454ef 100644 --- a/src/main/java/net/rubyeye/xmemcached/utils/ByteUtils.java +++ b/src/main/java/net/rubyeye/xmemcached/utils/ByteUtils.java @@ -48,6 +48,10 @@ public final class ByteUtils { private ByteUtils() { } + public static boolean isValidString(String s) { + return s != null && s.trim().length() > 0; + } + public static boolean isNumber(String string) { if (string == null || string.isEmpty()) { return false; diff --git a/src/main/java/net/rubyeye/xmemcached/utils/InetSocketAddressWrapper.java b/src/main/java/net/rubyeye/xmemcached/utils/InetSocketAddressWrapper.java index 853fce18e..f2c331710 100644 --- a/src/main/java/net/rubyeye/xmemcached/utils/InetSocketAddressWrapper.java +++ b/src/main/java/net/rubyeye/xmemcached/utils/InetSocketAddressWrapper.java @@ -39,7 +39,7 @@ public void setRemoteAddressStr(String remoteAddressStr) { } public final InetSocketAddress getInetSocketAddress() { - if (isValidHostName(this.hostName)) { + if (ByteUtils.isValidString(this.hostName)) { // If it has a hostName, we try to resolve it again. return new InetSocketAddress(this.hostName, this.inetSocketAddress.getPort()); @@ -48,10 +48,6 @@ public final InetSocketAddress getInetSocketAddress() { } } - private boolean isValidHostName(String h) { - return h != null && h.trim().length() > 0; - } - public final void setInetSocketAddress(InetSocketAddress inetSocketAddress) { this.inetSocketAddress = inetSocketAddress; if (inetSocketAddress != null) { @@ -72,7 +68,7 @@ public void setWeight(int weight) { } public InetSocketAddress getMainNodeAddress() { - if (this.isValidHostName(this.mainNodeHostName)) { + if (ByteUtils.isValidString(this.mainNodeHostName)) { return new InetSocketAddress(this.mainNodeHostName, this.mainNodeAddress.getPort()); } else { From 4dca57581cd63219e3f3bab832328abffbb78fe2 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Thu, 27 Oct 2016 13:52:33 +0800 Subject: [PATCH 080/207] [maven-release-plugin] prepare release xmemcached-2.2.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ee22bd7f2..a8468f6f0 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ 4.0.0 com.googlecode.xmemcached xmemcached - 2.1.1-SNAPSHOT + 2.2.0 xmemcached Extreme performance modern memcached client for java https://github.com/killme2008/xmemcached From 12151b42cd657a0f3d5b875b85efc80cd4657aee Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Thu, 27 Oct 2016 13:52:53 +0800 Subject: [PATCH 081/207] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a8468f6f0..bf1c61e2d 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ 4.0.0 com.googlecode.xmemcached xmemcached - 2.2.0 + 2.2.1-SNAPSHOT xmemcached Extreme performance modern memcached client for java https://github.com/killme2008/xmemcached From 8891ae7c9beac202ea2f975e03ae292d955739cb Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Thu, 27 Oct 2016 14:51:42 +0800 Subject: [PATCH 082/207] (feat) Adds news to readme --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 98166ed58..18a05667d 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,11 @@ Quick start: * [Getting started](https://github.com/killme2008/xmemcached/wiki/Getting%20started) * [快速入门](https://github.com/killme2008/xmemcached/wiki/%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8) + +#News + +* [2.2.0](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.2.0) released, highly recommended upgrading. + ## Contributors From c7e1b1ece02996936d6519a497723b0e7c494df5 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Thu, 27 Oct 2016 17:52:31 +0800 Subject: [PATCH 083/207] (fix) fix by test --- .../rubyeye/xmemcached/XMemcachedClient.java | 24 +++++++---- .../xmemcached/aws/AWSElasticCacheClient.java | 27 +++++++++++- .../xmemcached/aws/ClusterConfigration.java | 10 ++--- .../TextAWSElasticCacheConfigCommand.java | 34 +++++++++------ .../xmemcached/impl/MemcachedConnector.java | 42 +++++++++++-------- 5 files changed, 91 insertions(+), 46 deletions(-) diff --git a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java index e5da577fc..d24d19fc3 100644 --- a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java +++ b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java @@ -549,8 +549,7 @@ protected void removeAddr(InetSocketAddress address) { for (Session session : sessionQueue) { if (session != null) { // Disable auto reconnection - ((MemcachedSession) session) - .setAllowReconnect(false); + ((MemcachedSession) session).setAllowReconnect(false); // Close connection ((MemcachedSession) session).quit(); } @@ -565,8 +564,7 @@ protected void removeAddr(InetSocketAddress address) { this.connector.removeReconnectRequest(session .getRemoteSocketAddress()); // Disable auto reconnection - ((MemcachedSession) session) - .setAllowReconnect(false); + ((MemcachedSession) session).setAllowReconnect(false); // Close connection ((MemcachedSession) session).quit(); } @@ -575,7 +573,8 @@ protected void removeAddr(InetSocketAddress address) { this.connector.removeReconnectRequest(address); } - protected void connect(final InetSocketAddressWrapper inetSocketAddressWrapper) + protected void connect( + final InetSocketAddressWrapper inetSocketAddressWrapper) throws IOException { // creat connection pool InetSocketAddress inetSocketAddress = inetSocketAddressWrapper @@ -803,7 +802,7 @@ public final void setBufferAllocator(final BufferAllocator bufferAllocator) { * @throws IOException */ public XMemcachedClient(final InetSocketAddress inetSocketAddress, - int weight) throws IOException { + int weight, CommandFactory cmdFactory) throws IOException { super(); if (inetSocketAddress == null) { throw new IllegalArgumentException("Null InetSocketAddress"); @@ -815,13 +814,18 @@ public XMemcachedClient(final InetSocketAddress inetSocketAddress, this.buildConnector(new ArrayMemcachedSessionLocator(), new SimpleBufferAllocator(), XMemcachedClientBuilder.getDefaultConfiguration(), - XMemcachedClientBuilder.getDefaultSocketOptions(), - new TextCommandFactory(), new SerializingTranscoder()); + XMemcachedClientBuilder.getDefaultSocketOptions(), cmdFactory, + new SerializingTranscoder()); this.start0(); this.connect(new InetSocketAddressWrapper(inetSocketAddress, this.serverOrderCount.incrementAndGet(), weight, null)); } + public XMemcachedClient(final InetSocketAddress inetSocketAddress, + int weight) throws IOException { + this(inetSocketAddress, weight, new TextCommandFactory()); + } + public XMemcachedClient(final InetSocketAddress inetSocketAddress) throws IOException { this(inetSocketAddress, 1); @@ -1925,7 +1929,8 @@ private boolean delete0(String key, final int time, long cas, return (Boolean) command.getResult(); } - protected void checkException(final Command command) throws MemcachedException { + protected void checkException(final Command command) + throws MemcachedException { if (command.getException() != null) { if (command.getException() instanceof MemcachedException) { throw (MemcachedException) command.getException(); @@ -2403,6 +2408,7 @@ public final void shutdown() throws IOException { return; } this.shutdown = true; + this.connector.shuttingDown(); this.connector.quitAllSessions(); this.connector.stop(); this.memcachedHandler.stop(); diff --git a/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java b/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java index 8bedd8399..cee4c190e 100644 --- a/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java +++ b/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java @@ -7,13 +7,25 @@ import java.util.List; import java.util.concurrent.TimeoutException; +import javax.xml.soap.SOAPElement; +import javax.xml.soap.SOAPException; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.w3c.dom.DOMException; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; +import org.w3c.dom.UserDataHandler; import com.google.code.yanf4j.core.Session; +import net.rubyeye.xmemcached.CommandFactory; import net.rubyeye.xmemcached.XMemcachedClient; import net.rubyeye.xmemcached.command.Command; +import net.rubyeye.xmemcached.command.TextCommandFactory; import net.rubyeye.xmemcached.exception.MemcachedException; import net.rubyeye.xmemcached.utils.InetSocketAddressWrapper; @@ -91,10 +103,23 @@ private void removeConfigAddr() { private final ConfigurationPoller configPoller; + public static final long DEFAULT_POLL_CONFIG_INTERVAL_MS = 60000; + + public AWSElasticCacheClient(InetSocketAddress addr) throws IOException { + this(addr, DEFAULT_POLL_CONFIG_INTERVAL_MS); + } + public AWSElasticCacheClient(InetSocketAddress addr, long pollConfigIntervalMills) throws IOException { - super(addr); + this(addr, pollConfigIntervalMills, new TextCommandFactory()); + } + + public AWSElasticCacheClient(InetSocketAddress addr, + long pollConfigIntervalMills, CommandFactory commandFactory) + throws IOException { + super(addr, 1, commandFactory); // Use failure mode by default. + this.commandFactory = commandFactory; this.setFailureMode(true); this.configAddr = addr; this.configPoller = new ConfigurationPoller(this, diff --git a/src/main/java/net/rubyeye/xmemcached/aws/ClusterConfigration.java b/src/main/java/net/rubyeye/xmemcached/aws/ClusterConfigration.java index 583eb42f9..27f09eae1 100644 --- a/src/main/java/net/rubyeye/xmemcached/aws/ClusterConfigration.java +++ b/src/main/java/net/rubyeye/xmemcached/aws/ClusterConfigration.java @@ -41,14 +41,12 @@ public ClusterConfigration(int version, List nodeList) { public ClusterConfigration() { super(); } - public String toString() { - StringBuilder nodeList = new StringBuilder("Version:" + version - + " CacheNode List:"); - for (CacheNode node : this.nodeList) { - nodeList.append(" " + node.getHostName() + ":" + node.getPort()); - } + StringBuilder nodeList = new StringBuilder("{ Version: " + version + + ", CacheNode List: "); + nodeList.append(this.nodeList); + nodeList.append("}"); return nodeList.toString(); } diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextAWSElasticCacheConfigCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextAWSElasticCacheConfigCommand.java index f2e7f5695..ed01581cc 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextAWSElasticCacheConfigCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextAWSElasticCacheConfigCommand.java @@ -5,10 +5,10 @@ import com.google.code.yanf4j.buffer.IoBuffer; -import net.rubyeye.xmemcached.aws.AWSUtils; import net.rubyeye.xmemcached.command.Command; import net.rubyeye.xmemcached.command.CommandType; import net.rubyeye.xmemcached.impl.MemcachedTCPSession; +import net.rubyeye.xmemcached.networking.MemcachedSession; import net.rubyeye.xmemcached.utils.ByteUtils; /** @@ -28,23 +28,31 @@ public class TextAWSElasticCacheConfigCommand extends Command { public TextAWSElasticCacheConfigCommand(final CountDownLatch latch, String subCommand, String key) { - super(CommandType.AWS_CONFIG, latch); + super(subCommand + key, CommandType.AWS_CONFIG, latch); this.key = key; this.subCommand = subCommand; + this.result = new StringBuilder(); } @Override public boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { - if (buffer == null || !buffer.hasRemaining()) { - return false; - } - String line = ByteUtils.nextLine(buffer); - if (line != null) { - setResult(line); - return true; - } else { - return false; + String line = null; + while ((line = ByteUtils.nextLine(buffer)) != null) { + if (line.equals("END")) { // at the end + return done(session); + } else if (line.startsWith("CONFIG")) { + // ignore + } else { + ((StringBuilder) this.getResult()).append(line); + } } + return false; + } + + private final boolean done(MemcachedSession session) { + setResult(this.getResult().toString()); + countDownLatch(); + return true; } @Override @@ -52,8 +60,8 @@ public void encode() { // config [sub-command] [key] final byte[] subCmdBytes = ByteUtils.getBytes(this.subCommand); final byte[] keyBytes = ByteUtils.getBytes(this.key); - this.ioBuffer = IoBuffer.allocate(5 + 1 + subCmdBytes.length + 1 - + +keyBytes.length); + this.ioBuffer = IoBuffer.allocate(6 + 1 + subCmdBytes.length + 1 + + +keyBytes.length + 2); ByteUtils.setArguments(this.ioBuffer, "config", subCmdBytes, keyBytes); this.ioBuffer.flip(); } diff --git a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java index 8e2ee8388..caf006cd8 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java @@ -65,7 +65,7 @@ * @author dennis */ public class MemcachedConnector extends SocketChannelController implements -Connector { + Connector { private final DelayQueue waitingQueue = new DelayQueue(); private BufferAllocator bufferAllocator; @@ -80,12 +80,18 @@ public class MemcachedConnector extends SocketChannelController implements private boolean failureMode; private final ConcurrentHashMap/* - * standby - * sessions - */> standbySessionMap = new ConcurrentHashMap>(); + * standby + * sessions + */> standbySessionMap = new ConcurrentHashMap>(); private final FlowControl flowControl; + private volatile boolean shuttingDown = false; + + public void shuttingDown() { + this.shuttingDown = true; + } + public void setSessionLocator(MemcachedSessionLocator sessionLocator) { this.sessionLocator = sessionLocator; } @@ -103,7 +109,8 @@ public SessionMonitor() { @Override public void run() { - while (MemcachedConnector.this.isStarted() && MemcachedConnector.this.enableHealSession) { + while (MemcachedConnector.this.isStarted() + && MemcachedConnector.this.enableHealSession) { ReconnectRequest request = null; try { request = MemcachedConnector.this.waitingQueue.take(); @@ -172,7 +179,7 @@ private void rescheduleConnectRequest(ReconnectRequest request) { public void setEnableHealSession(boolean enableHealSession) { this.enableHealSession = enableHealSession; - //wake up session monitor thread. + // wake up session monitor thread. if (this.sessionMonitor != null && this.sessionMonitor.isAlive()) { this.sessionMonitor.interrupt(); } @@ -206,7 +213,7 @@ public void setOptimizeGet(boolean optimiezeGet) { public void setOptimizeMergeBuffer(boolean optimizeMergeBuffer) { ((OptimizerMBean) this.optimiezer) - .setOptimizeMergeBuffer(optimizeMergeBuffer); + .setOptimizeMergeBuffer(optimizeMergeBuffer); } public Protocol getProtocol() { @@ -215,7 +222,6 @@ public Protocol getProtocol() { protected MemcachedSessionLocator sessionLocator; - protected final ConcurrentHashMap> sessionMap = new ConcurrentHashMap>(); public synchronized void addSession(Session session) { @@ -319,7 +325,7 @@ public void removeReconnectRequest(InetSocketAddress inetSocketAddress) { it.remove(); log.warn("Remove invalid reconnect task for " + request.getInetSocketAddressWrapper() - .getInetSocketAddress()); + .getInetSocketAddress()); } } } @@ -353,7 +359,8 @@ private void removeMainSession(Session session) { InetSocketAddress remoteSocketAddress = session .getRemoteSocketAddress(); // If it was in failure mode,we don't remove closed session from list. - if (this.failureMode) { + if (this.failureMode && ((MemcachedSession) session).isAllowReconnect() + && !this.shuttingDown && this.isStarted()) { log.warn("Client in failure mode,we don't remove session " + SystemUtils.getRawAddress(remoteSocketAddress) + ":" + remoteSocketAddress.getPort()); @@ -404,8 +411,8 @@ public void onConnect(SelectionKey key) throws IOException { + SystemUtils.getRawAddress(future .getInetSocketAddressWrapper() .getInetSocketAddress()) - + ":" - + future.getInetSocketAddressWrapper() + + ":" + + future.getInetSocketAddressWrapper() .getInetSocketAddress().getPort() + " fail")); } else { key.attach(null); @@ -421,10 +428,10 @@ public void onConnect(SelectionKey key) throws IOException { + SystemUtils.getRawAddress(future .getInetSocketAddressWrapper() .getInetSocketAddress()) - + ":" - + future.getInetSocketAddressWrapper() + + ":" + + future.getInetSocketAddressWrapper() .getInetSocketAddress().getPort() + " fail," - + e.getMessage()); + + e.getMessage()); } } @@ -503,8 +510,8 @@ public Session send(final Command msg) throws MemcachedException { throw new MemcachedException("Session(" + SystemUtils.getRawAddress(session .getRemoteSocketAddress()) + ":" - + session.getRemoteSocketAddress().getPort() - + ") has been closed"); + + session.getRemoteSocketAddress().getPort() + + ") has been closed"); } if (session.isAuthFailed()) { throw new MemcachedException("Auth failed to connection " @@ -539,6 +546,7 @@ public List getStandbySessionListByMainNodeAddr( } private final SessionMonitor sessionMonitor = new SessionMonitor(); + /** * Inner state listenner,manage session monitor. * From 6fb489eacf96c05264ee6f07a8186190549d5d34 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Thu, 27 Oct 2016 17:58:28 +0800 Subject: [PATCH 084/207] (fix) Remove imports --- .../rubyeye/xmemcached/aws/AWSElasticCacheClient.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java b/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java index cee4c190e..d73d0ba3f 100644 --- a/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java +++ b/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java @@ -7,18 +7,8 @@ import java.util.List; import java.util.concurrent.TimeoutException; -import javax.xml.soap.SOAPElement; -import javax.xml.soap.SOAPException; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.w3c.dom.DOMException; -import org.w3c.dom.Document; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.w3c.dom.Text; -import org.w3c.dom.UserDataHandler; import com.google.code.yanf4j.core.Session; From 4af068cc52b3c48aebf01fe2aa7417e1cc832734 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Thu, 3 Nov 2016 10:42:33 +0800 Subject: [PATCH 085/207] (feat) Adds more constructors for AWSElasticCacheClient --- .../rubyeye/xmemcached/XMemcachedClient.java | 24 +++++++- .../xmemcached/aws/AWSElasticCacheClient.java | 55 ++++++++++++++----- 2 files changed, 64 insertions(+), 15 deletions(-) diff --git a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java index d24d19fc3..946828509 100644 --- a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java +++ b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java @@ -808,6 +808,9 @@ public XMemcachedClient(final InetSocketAddress inetSocketAddress, throw new IllegalArgumentException("Null InetSocketAddress"); } + if (cmdFactory == null) { + throw new IllegalArgumentException("Null command factory."); + } if (weight <= 0) { throw new IllegalArgumentException("weight<=0"); } @@ -1002,7 +1005,24 @@ private final boolean isWindowsPlatform() { */ public XMemcachedClient(List addressList) throws IOException { + this(addressList, new TextCommandFactory()); + } + + /** + * XMemcached Constructor.Every server's weight is one by default. + * + * @param cmdFactory + * command factory + * @param addressList + * memcached server socket address list. + * @throws IOException + */ + public XMemcachedClient(List addressList, + CommandFactory cmdFactory) throws IOException { super(); + if (cmdFactory == null) { + throw new IllegalArgumentException("Null command factory."); + } if (addressList == null || addressList.isEmpty()) { throw new IllegalArgumentException("Empty address list"); } @@ -1010,8 +1030,8 @@ public XMemcachedClient(List addressList) this.buildConnector(new ArrayMemcachedSessionLocator(), simpleBufferAllocator, XMemcachedClientBuilder.getDefaultConfiguration(), - XMemcachedClientBuilder.getDefaultSocketOptions(), - new TextCommandFactory(), new SerializingTranscoder()); + XMemcachedClientBuilder.getDefaultSocketOptions(), cmdFactory, + new SerializingTranscoder()); this.start0(); for (InetSocketAddress inetSocketAddress : addressList) { this.connect(new InetSocketAddressWrapper(inetSocketAddress, diff --git a/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java b/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java index d73d0ba3f..2c7203253 100644 --- a/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java +++ b/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java @@ -33,13 +33,13 @@ public class AWSElasticCacheClient extends XMemcachedClient implements private boolean firstTimeUpdate = true; - private InetSocketAddress configAddr; + private List configAddrs = new ArrayList(); public synchronized void onUpdate(ClusterConfigration config) { if (firstTimeUpdate) { firstTimeUpdate = false; - removeConfigAddr(); + removeConfigAddrs(); } List oldList = this.currentClusterConfiguration != null ? this.currentClusterConfiguration @@ -79,14 +79,17 @@ public synchronized void onUpdate(ClusterConfigration config) { this.currentClusterConfiguration = config; } - private void removeConfigAddr() { - this.removeAddr(configAddr); - while (this.getConnector().getSessionByAddress(configAddr) != null - && this.getConnector().getSessionByAddress(configAddr).size() > 0) { - try { - Thread.sleep(50); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); + private void removeConfigAddrs() { + for (InetSocketAddress configAddr : this.configAddrs) { + this.removeAddr(configAddr); + while (this.getConnector().getSessionByAddress(configAddr) != null + && this.getConnector().getSessionByAddress(configAddr) + .size() > 0) { + try { + Thread.sleep(50); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } } } } @@ -105,13 +108,39 @@ public AWSElasticCacheClient(InetSocketAddress addr, } public AWSElasticCacheClient(InetSocketAddress addr, + long pollConfigIntervalMills, CommandFactory cmdFactory) + throws IOException { + this(asList(addr), pollConfigIntervalMills, cmdFactory); + } + + private static List asList(InetSocketAddress addr) { + List addrs = new ArrayList(); + addrs.add(addr); + return addrs; + } + + public AWSElasticCacheClient(List addrs) + throws IOException { + this(addrs, DEFAULT_POLL_CONFIG_INTERVAL_MS); + } + + public AWSElasticCacheClient(List addrs, + long pollConfigIntervalMills) throws IOException { + this(addrs, pollConfigIntervalMills, new TextCommandFactory()); + } + + public AWSElasticCacheClient(List addrs, long pollConfigIntervalMills, CommandFactory commandFactory) throws IOException { - super(addr, 1, commandFactory); + super(addrs, commandFactory); + if (pollConfigIntervalMills <= 0) { + throw new IllegalArgumentException( + "Invalid pollConfigIntervalMills value."); + } // Use failure mode by default. this.commandFactory = commandFactory; this.setFailureMode(true); - this.configAddr = addr; + this.configAddrs = addrs; this.configPoller = new ConfigurationPoller(this, pollConfigIntervalMills); // Run at once to get config at startup. @@ -119,7 +148,7 @@ public AWSElasticCacheClient(InetSocketAddress addr, this.configPoller.run(); if (this.currentClusterConfiguration == null) { throw new IllegalStateException( - "Retrieve ElasticCache config from `" + addr.toString() + "Retrieve ElasticCache config from `" + addrs.toString() + "` failed."); } this.configPoller.start(); From b83b4266b0a9df5e4122f74a019f5124347b9215 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Thu, 3 Nov 2016 10:47:47 +0800 Subject: [PATCH 086/207] [maven-release-plugin] prepare release xmemcached-2.2.1-beta --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ee22bd7f2..79a8a205f 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ 4.0.0 com.googlecode.xmemcached xmemcached - 2.1.1-SNAPSHOT + 2.2.1-beta xmemcached Extreme performance modern memcached client for java https://github.com/killme2008/xmemcached From d84f9e6e2f49f5a25caf37da5273dc741507b624 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Thu, 3 Nov 2016 10:48:00 +0800 Subject: [PATCH 087/207] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 79a8a205f..bf1c61e2d 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ 4.0.0 com.googlecode.xmemcached xmemcached - 2.2.1-beta + 2.2.1-SNAPSHOT xmemcached Extreme performance modern memcached client for java https://github.com/killme2008/xmemcached From e9411de260bead7ab48eda03341b923dc2a1d268 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Wed, 22 Feb 2017 19:11:55 +0800 Subject: [PATCH 088/207] (fix) Fixed NPE in rescheduleConnectRequest, close #53 --- .../java/net/rubyeye/xmemcached/impl/MemcachedConnector.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java index 8e2ee8388..c1dffec06 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java @@ -163,8 +163,7 @@ private void rescheduleConnectRequest(ReconnectRequest request) { // update timestamp for next reconnecting request.updateNextReconnectTimeStamp(MemcachedConnector.this.healSessionInterval * request.getTries()); - log.error("Reconnect to " + address.getAddress().getHostAddress() - + ":" + address.getPort() + " fail"); + log.error("Reconnected to " + address + " fail"); // add to tail MemcachedConnector.this.waitingQueue.offer(request); } From e263077596d02aa39d549d3042e01b949eba5baf Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Wed, 22 Feb 2017 19:13:01 +0800 Subject: [PATCH 089/207] (fix) typo in setConnectionPoolSize, close #52 --- .../java/net/rubyeye/xmemcached/MemcachedClientBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/rubyeye/xmemcached/MemcachedClientBuilder.java b/src/main/java/net/rubyeye/xmemcached/MemcachedClientBuilder.java index 665a31738..6cc1fae36 100644 --- a/src/main/java/net/rubyeye/xmemcached/MemcachedClientBuilder.java +++ b/src/main/java/net/rubyeye/xmemcached/MemcachedClientBuilder.java @@ -72,7 +72,7 @@ public interface MemcachedClientBuilder { * In a high concurrent enviroment,you may want to pool memcached * clients.But a xmemcached client has to start a reactor thread and some * thread pools,if you create too many clients,the cost is very large. - * Xmemcached supports connection pool instreadof client pool.you can create + * Xmemcached supports connection pool instead of client pool.you can create * more connections to one or more memcached servers,and these connections * share the same reactor and thread pools,it will reduce the cost of * system. From 8cf19937c4a03e04305759e7891c7829ade123c9 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Mon, 27 Feb 2017 22:09:14 +0800 Subject: [PATCH 090/207] (feat) tweak --- .../xmemcached/aws/AWSElasticCacheClient.java | 67 +++++++++++++++++-- .../TextAWSElasticCacheConfigCommand.java | 2 +- 2 files changed, 64 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java b/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java index 2c7203253..9def16f96 100644 --- a/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java +++ b/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java @@ -22,6 +22,7 @@ /** * AWS ElasticCache Client. * + * @since 2.3.0 * @author dennis * */ @@ -73,7 +74,11 @@ public synchronized void onUpdate(ClusterConfigration config) { } for (CacheNode node : removeNodes) { - this.removeAddr(node.getInetSocketAddress()); + try { + this.removeAddr(node.getInetSocketAddress()); + } catch (Exception e) { + log.error("Remove " + node + " failed."); + } } this.currentClusterConfiguration = config; @@ -86,7 +91,7 @@ private void removeConfigAddrs() { && this.getConnector().getSessionByAddress(configAddr) .size() > 0) { try { - Thread.sleep(50); + Thread.sleep(10); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } @@ -96,12 +101,35 @@ private void removeConfigAddrs() { private final ConfigurationPoller configPoller; + /** + * Default elasticcache configuration poll interval, it's one minute. + */ public static final long DEFAULT_POLL_CONFIG_INTERVAL_MS = 60000; + /** + * Construct an AWSElasticCacheClient instance with one config address and + * default poll interval. + * + * @since 2.3.0 + * @param addr + * config server address. + * @throws IOException + */ public AWSElasticCacheClient(InetSocketAddress addr) throws IOException { this(addr, DEFAULT_POLL_CONFIG_INTERVAL_MS); } + /** + * Construct an AWSElasticCacheClient instance with one config address and + * poll interval. + * + * @since 2.3.0 + * @param addr + * config server address. + * @param pollConfigIntervalMills + * config poll interval in milliseconds. + * @throws IOException + */ public AWSElasticCacheClient(InetSocketAddress addr, long pollConfigIntervalMills) throws IOException { this(addr, pollConfigIntervalMills, new TextCommandFactory()); @@ -119,16 +147,45 @@ private static List asList(InetSocketAddress addr) { return addrs; } + /** + * Construct an AWSElasticCacheClient instance with config server addresses + * and default config poll interval. + * + * @since 2.3.0 + * @param addrs + * config server list. + * @throws IOException + */ public AWSElasticCacheClient(List addrs) throws IOException { this(addrs, DEFAULT_POLL_CONFIG_INTERVAL_MS); } + /** + * Construct an AWSElasticCacheClient instance with config server addresses. + * + * @since 2.3.0 + * @param addrs + * @param pollConfigIntervalMills + * @throws IOException + */ public AWSElasticCacheClient(List addrs, long pollConfigIntervalMills) throws IOException { this(addrs, pollConfigIntervalMills, new TextCommandFactory()); } + /** + * Construct an AWSElasticCacheClient instance with config server addresses. + * + * @since 2.3.0 + * @param addrs + * config server list. + * @param pollConfigIntervalMills + * config poll interval in milliseconds. + * @param commandFactory + * protocol command factory. + * @throws IOException + */ public AWSElasticCacheClient(List addrs, long pollConfigIntervalMills, CommandFactory commandFactory) throws IOException { @@ -169,7 +226,8 @@ public ClusterConfigration getConfig() throws MemcachedException, /** * Get config by key from cache node by network command. * - * @return + * @since 2.3.0 + * @return clusetr config. */ public ClusterConfigration getConfig(String key) throws MemcachedException, InterruptedException, TimeoutException { @@ -190,7 +248,8 @@ public ClusterConfigration getConfig(String key) throws MemcachedException, /** * Get the current using configuration in memory. * - * @return + * @since 2.3.0 + * @return current cluster config. */ public ClusterConfigration getCurrentConfig() { return this.currentClusterConfiguration; diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextAWSElasticCacheConfigCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextAWSElasticCacheConfigCommand.java index ed01581cc..4bac2df4f 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextAWSElasticCacheConfigCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextAWSElasticCacheConfigCommand.java @@ -61,7 +61,7 @@ public void encode() { final byte[] subCmdBytes = ByteUtils.getBytes(this.subCommand); final byte[] keyBytes = ByteUtils.getBytes(this.key); this.ioBuffer = IoBuffer.allocate(6 + 1 + subCmdBytes.length + 1 - + +keyBytes.length + 2); + + keyBytes.length + 2); ByteUtils.setArguments(this.ioBuffer, "config", subCmdBytes, keyBytes); this.ioBuffer.flip(); } From e01e5a239169dd4853c06a37f9b6922282898a10 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Mon, 27 Feb 2017 22:46:40 +0800 Subject: [PATCH 091/207] (feat) Adds AWSElasticCacheClientIT test --- .../unittest/AWSElasticCacheClientIT.java | 151 ++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 src/test/java/net/rubyeye/xmemcached/test/unittest/AWSElasticCacheClientIT.java diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/AWSElasticCacheClientIT.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/AWSElasticCacheClientIT.java new file mode 100644 index 000000000..d75cf443c --- /dev/null +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/AWSElasticCacheClientIT.java @@ -0,0 +1,151 @@ +package net.rubyeye.xmemcached.test.unittest; + +import java.net.InetSocketAddress; +import java.util.List; +import java.util.Properties; + +import net.rubyeye.xmemcached.aws.AWSElasticCacheClient; +import net.rubyeye.xmemcached.aws.ClusterConfigration; +import net.rubyeye.xmemcached.utils.AddrUtil; + +import org.junit.Test; + +import com.google.code.yanf4j.core.Session; +import com.google.code.yanf4j.core.impl.HandlerAdapter; +import com.google.code.yanf4j.core.impl.TextLineCodecFactory; +import com.google.code.yanf4j.nio.TCPController; +import com.google.code.yanf4j.util.ResourcesUtils; + +import junit.framework.TestCase; + +public class AWSElasticCacheClientIT extends TestCase { + + private String serverList; + private List addresses; + + /** + * elasticcache config node mock handler + * + * @author dennis + * + */ + private static final class MockHandler extends HandlerAdapter { + private final String response; + private int version; + + public MockHandler(int version, String response) { + super(); + this.response = response; + this.version = version; + } + + @Override + public void onMessageReceived(Session session, Object message) { + if (message.equals("quit")) { + session.close(); + return; + } + session.write("CONFIG cluster 0 " + this.response.length()); + session.write(String.valueOf(version) + "\n" + this.response); + session.write("END"); + this.version++; + } + + } + + @Override + public void setUp() throws Exception { + Properties properties = ResourcesUtils + .getResourceAsProperties("test.properties"); + List addresses = AddrUtil.getAddresses(properties + .getProperty("test.memcached.servers")); + StringBuffer sb = new StringBuffer(); + boolean wasFirst = true; + for (InetSocketAddress addr : addresses) { + if (wasFirst) { + wasFirst = false; + } else { + sb.append(" "); + } + sb.append(addr.getHostString() + "|" + addr.getHostString() + "|" + + addr.getPort()); + + } + + this.addresses = addresses; + serverList = sb.toString(); + } + + @Test + public void testInvalidConfig() throws Exception { + TCPController configServer = new TCPController(); + int version = 10; + configServer.setHandler(new MockHandler(version, "invalid")); + configServer.setCodecFactory(new TextLineCodecFactory()); + configServer.bind(new InetSocketAddress(2271)); + + try { + AWSElasticCacheClient client = new AWSElasticCacheClient( + new InetSocketAddress(2271)); + fail(); + } catch (IllegalStateException e) { + assert (e.getMessage().contains("Invalid server")); + } finally { + configServer.stop(); + } + } + + @Test + public void testPollConfigAndUsage() throws Exception { + TCPController configServer = new TCPController(); + int version = 10; + configServer.setHandler(new MockHandler(version, serverList)); + configServer.setCodecFactory(new TextLineCodecFactory()); + configServer.bind(new InetSocketAddress(2271)); + + try { + AWSElasticCacheClient client = new AWSElasticCacheClient( + new InetSocketAddress(2271)); + ClusterConfigration config = client.getCurrentConfig(); + assertEquals(config.getVersion(), version); + assertEquals(addresses.size(), config.getNodeList().size()); + + client.set("aws-cache", 0, "foobar"); + assertEquals("foobar", client.get("aws-cache")); + } finally { + configServer.stop(); + } + } + + @Test + public void testPollConfigInterval() throws Exception { + TCPController cs1 = new TCPController(); + int version = 10; + cs1.setHandler(new MockHandler(version, "localhost|localhost|2272")); + cs1.setCodecFactory(new TextLineCodecFactory()); + cs1.bind(new InetSocketAddress(2271)); + TCPController cs2 = new TCPController(); + cs2.setHandler(new MockHandler(version + 1, + "localhost|localhost|2271 localhost|localhost|2272")); + cs2.setCodecFactory(new TextLineCodecFactory()); + cs2.bind(new InetSocketAddress(2272)); + + try { + AWSElasticCacheClient client = new AWSElasticCacheClient( + new InetSocketAddress(2271), 3000); + ClusterConfigration config = client.getCurrentConfig(); + assertEquals(config.getVersion(), version); + assertEquals(1, config.getNodeList().size()); + assertEquals(2272, config.getNodeList().get(0).getPort()); + Thread.sleep(3500); + config = client.getCurrentConfig(); + assertEquals(config.getVersion(), version + 1); + assertEquals(2, config.getNodeList().size()); + assertEquals(2271, config.getNodeList().get(0).getPort()); + assertEquals(2272, config.getNodeList().get(1).getPort()); + } finally { + cs1.stop(); + cs2.stop(); + } + } +} From dcff894a923601fdb399d8de7e5f1647bdba5d4b Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Mon, 27 Feb 2017 22:47:37 +0800 Subject: [PATCH 092/207] (feat) Bump to 2.3.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bf1c61e2d..ad1ff2d31 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ 4.0.0 com.googlecode.xmemcached xmemcached - 2.2.1-SNAPSHOT + 2.3.0-SNAPSHOT xmemcached Extreme performance modern memcached client for java https://github.com/killme2008/xmemcached From eef7bcbe4341da1a9bad3e5b30781bf1e381ec90 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Mon, 27 Feb 2017 22:55:08 +0800 Subject: [PATCH 093/207] (fix) compatible with JDK 1.6 --- .../xmemcached/test/unittest/AWSElasticCacheClientIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/AWSElasticCacheClientIT.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/AWSElasticCacheClientIT.java index d75cf443c..33d42c0b7 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/AWSElasticCacheClientIT.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/AWSElasticCacheClientIT.java @@ -67,7 +67,7 @@ public void setUp() throws Exception { } else { sb.append(" "); } - sb.append(addr.getHostString() + "|" + addr.getHostString() + "|" + sb.append(addr.getHostName() + "|" + addr.getHostName() + "|" + addr.getPort()); } From c506ebcbe84d3c5110d201f2291cdf1a47f457e9 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Tue, 28 Feb 2017 00:35:06 +0800 Subject: [PATCH 094/207] (fix) test --- .../xmemcached/test/unittest/AWSElasticCacheClientIT.java | 2 +- .../test/unittest/StandardHashMemcachedClientIT.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/AWSElasticCacheClientIT.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/AWSElasticCacheClientIT.java index 33d42c0b7..9c36d0d15 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/AWSElasticCacheClientIT.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/AWSElasticCacheClientIT.java @@ -89,7 +89,7 @@ public void testInvalidConfig() throws Exception { new InetSocketAddress(2271)); fail(); } catch (IllegalStateException e) { - assert (e.getMessage().contains("Invalid server")); + assertTrue(e.getMessage().contains("failed")); } finally { configServer.stop(); } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/StandardHashMemcachedClientIT.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/StandardHashMemcachedClientIT.java index 1c1058726..899572a8f 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/StandardHashMemcachedClientIT.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/StandardHashMemcachedClientIT.java @@ -190,9 +190,9 @@ public void testDecrWithNoReply() throws Exception { assertTrue(memcachedClient.set("a", 0, "100")); memcachedClient.decrWithNoReply("a", 50); - assertEquals("50", memcachedClient.get("a")); + assertEquals("50", ((String) memcachedClient.get("a")).trim()); memcachedClient.decrWithNoReply("a", 4); - assertEquals("46", memcachedClient.get("a")); + assertEquals("46", ((String) memcachedClient.get("a")).trim()); } @Override From e17bb49eb9d8315654b3f676d77cd7810b87896f Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Tue, 28 Feb 2017 00:41:53 +0800 Subject: [PATCH 095/207] [maven-release-plugin] prepare release xmemcached-2.3.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ad1ff2d31..5d294e22c 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ 4.0.0 com.googlecode.xmemcached xmemcached - 2.3.0-SNAPSHOT + 2.3.0 xmemcached Extreme performance modern memcached client for java https://github.com/killme2008/xmemcached From 2efc3633a7c7c719f3c12e03e9f43f9f90641a59 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Tue, 28 Feb 2017 00:42:01 +0800 Subject: [PATCH 096/207] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5d294e22c..836e48d0b 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ 4.0.0 com.googlecode.xmemcached xmemcached - 2.3.0 + 2.3.1-SNAPSHOT xmemcached Extreme performance modern memcached client for java https://github.com/killme2008/xmemcached From f3e739145fbd3a571d09d7e023686001ed1abeef Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Tue, 28 Feb 2017 15:29:03 +0800 Subject: [PATCH 097/207] (feat) update readme --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 18a05667d..f3697e17b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ [![Build Status](https://travis-ci.org/killme2008/xmemcached.svg?branch=master)](https://travis-ci.org/killme2008/xmemcached) +#News + +* [2.3.0](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.0) released, suppports [AWS ElasticCache Auto Discovery](http://docs.aws.amazon.com/AmazonElastiCache/latest/UserGuide/AutoDiscovery.html). +* [2.2.0](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.2.0) released, highly recommended upgrading. + ##Introduction XMemcached is a high performance, easy to use blocking multithreaded memcached client in java. @@ -16,11 +21,6 @@ Quick start: * [Getting started](https://github.com/killme2008/xmemcached/wiki/Getting%20started) * [快速入门](https://github.com/killme2008/xmemcached/wiki/%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8) - -#News - -* [2.2.0](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.2.0) released, highly recommended upgrading. - ## Contributors From 9116c30526ce490011130bc6f767cc9a3a5ff5d0 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Sun, 12 Mar 2017 22:00:21 +0800 Subject: [PATCH 098/207] (feat) Adds AWSElasticCacheClientBuilder, #55 --- .../rubyeye/xmemcached/XMemcachedClient.java | 4 +- .../xmemcached/XMemcachedClientBuilder.java | 77 ++++++------- .../xmemcached/aws/AWSElasticCacheClient.java | 54 +++++++++- .../aws/AWSElasticCacheClientBuilder.java | 102 ++++++++++++++++++ .../unittest/AWSElasticCacheClientIT.java | 26 +++++ 5 files changed, 221 insertions(+), 42 deletions(-) create mode 100644 src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClientBuilder.java diff --git a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java index 946828509..20f8aee21 100644 --- a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java +++ b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java @@ -846,7 +846,7 @@ public XMemcachedClient() throws IOException { /** * XMemcachedClient constructor.Every server's weight is one by default. - * + * You should not new client instance by this method, use MemcachedClientBuilder instead. * @param locator * @param allocator * @param conf @@ -857,7 +857,7 @@ public XMemcachedClient() throws IOException { * @throws IOException */ @SuppressWarnings("unchecked") - XMemcachedClient(MemcachedSessionLocator locator, + public XMemcachedClient(MemcachedSessionLocator locator, BufferAllocator allocator, Configuration conf, Map socketOptions, CommandFactory commandFactory, Transcoder transcoder, diff --git a/src/main/java/net/rubyeye/xmemcached/XMemcachedClientBuilder.java b/src/main/java/net/rubyeye/xmemcached/XMemcachedClientBuilder.java index 5237a09bd..5191ad748 100644 --- a/src/main/java/net/rubyeye/xmemcached/XMemcachedClientBuilder.java +++ b/src/main/java/net/rubyeye/xmemcached/XMemcachedClientBuilder.java @@ -35,54 +35,55 @@ */ public class XMemcachedClientBuilder implements MemcachedClientBuilder { - private static final Logger log = LoggerFactory - .getLogger(XMemcachedClientBuilder.class); + private static final Logger log = LoggerFactory + .getLogger(XMemcachedClientBuilder.class); - private MemcachedSessionLocator sessionLocator = new ArrayMemcachedSessionLocator(); - private BufferAllocator bufferAllocator = new SimpleBufferAllocator(); - private Configuration configuration = getDefaultConfiguration(); - private Map addressMap = new LinkedHashMap(); + protected MemcachedSessionLocator sessionLocator = new ArrayMemcachedSessionLocator(); + protected BufferAllocator bufferAllocator = new SimpleBufferAllocator(); + protected Configuration configuration = getDefaultConfiguration(); + protected Map addressMap = new LinkedHashMap(); - private int[] weights; + protected int[] weights; - private long connectTimeout = MemcachedClient.DEFAULT_CONNECT_TIMEOUT; + protected long connectTimeout = MemcachedClient.DEFAULT_CONNECT_TIMEOUT; - private int connectionPoolSize = MemcachedClient.DEFAULT_CONNECTION_POOL_SIZE; + protected int connectionPoolSize = MemcachedClient.DEFAULT_CONNECTION_POOL_SIZE; @SuppressWarnings("unchecked") - final Map socketOptions = getDefaultSocketOptions(); + protected final Map socketOptions = getDefaultSocketOptions(); - private List stateListeners = new ArrayList(); + protected List stateListeners = new ArrayList(); - private Map authInfoMap = new HashMap(); + protected Map authInfoMap = new HashMap(); - private String name; + protected String name; - private boolean failureMode; + protected boolean failureMode; - private boolean sanitizeKeys; + protected boolean sanitizeKeys; - private KeyProvider keyProvider = DefaultKeyProvider.INSTANCE; + protected KeyProvider keyProvider = DefaultKeyProvider.INSTANCE; - private int maxQueuedNoReplyOperations = MemcachedClient.DEFAULT_MAX_QUEUED_NOPS; + protected int maxQueuedNoReplyOperations = MemcachedClient.DEFAULT_MAX_QUEUED_NOPS; - private long healSessionInterval = MemcachedClient.DEFAULT_HEAL_SESSION_INTERVAL; + protected long healSessionInterval = MemcachedClient.DEFAULT_HEAL_SESSION_INTERVAL; - private boolean enableHealSession = true; + protected boolean enableHealSession = true; - private long opTimeout = MemcachedClient.DEFAULT_OP_TIMEOUT; + protected long opTimeout = MemcachedClient.DEFAULT_OP_TIMEOUT; public long getOpTimeout() { - return opTimeout; - } + return opTimeout; + } public void setOpTimeout(long opTimeout) { - if (opTimeout <= 0) - throw new IllegalArgumentException("Invalid opTimeout value:"+opTimeout); - this.opTimeout = opTimeout; - } + if (opTimeout <= 0) + throw new IllegalArgumentException("Invalid opTimeout value:" + + opTimeout); + this.opTimeout = opTimeout; + } - public int getMaxQueuedNoReplyOperations() { + public int getMaxQueuedNoReplyOperations() { return maxQueuedNoReplyOperations; } @@ -169,7 +170,7 @@ public void setStateListeners( this.stateListeners = stateListeners; } - private CommandFactory commandFactory = new TextCommandFactory(); + protected CommandFactory commandFactory = new TextCommandFactory(); @SuppressWarnings("unchecked") public static final Map getDefaultSocketOptions() { @@ -196,7 +197,7 @@ public static final Configuration getDefaultConfiguration() { configuration .setSessionIdleTimeout(MemcachedClient.DEFAULT_SESSION_IDLE_TIMEOUT); configuration.setWriteThreadCount(0); - return configuration; + return configuration; } public boolean isFailureMode() { @@ -215,8 +216,8 @@ public final void setCommandFactory(CommandFactory commandFactory) { this.commandFactory = commandFactory; } - private @SuppressWarnings("unchecked") - Transcoder transcoder = new SerializingTranscoder(); + @SuppressWarnings({ "rawtypes" }) + protected Transcoder transcoder = new SerializingTranscoder(); public XMemcachedClientBuilder(String addressList) { this(AddrUtil.getAddresses(addressList)); @@ -357,6 +358,11 @@ public MemcachedClient build() throws IOException { this.authInfoMap, this.connectionPoolSize, this.connectTimeout, this.name, this.failureMode); } + this.configureClient(memcachedClient); + return memcachedClient; + } + + protected void configureClient(XMemcachedClient memcachedClient) { if (this.commandFactory.getProtocol() == Protocol.Kestrel) { memcachedClient.setOptimizeGet(false); } @@ -368,10 +374,9 @@ public MemcachedClient build() throws IOException { memcachedClient.setEnableHealSession(this.enableHealSession); memcachedClient .setMaxQueuedNoReplyOperations(this.maxQueuedNoReplyOperations); - return memcachedClient; } - @SuppressWarnings("unchecked") + @SuppressWarnings("rawtypes") public Transcoder getTranscoder() { return this.transcoder; } @@ -435,8 +440,8 @@ public void setName(String name) { } - public void setSelectorPoolSize(int selectorPoolSize) { - getConfiguration().setSelectorPoolSize(selectorPoolSize); - } + public void setSelectorPoolSize(int selectorPoolSize) { + getConfiguration().setSelectorPoolSize(selectorPoolSize); + } } diff --git a/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java b/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java index 9def16f96..a97e978d5 100644 --- a/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java +++ b/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java @@ -4,19 +4,32 @@ import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.TimeoutException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.code.yanf4j.config.Configuration; import com.google.code.yanf4j.core.Session; +import com.google.code.yanf4j.core.SocketOption; import net.rubyeye.xmemcached.CommandFactory; +import net.rubyeye.xmemcached.MemcachedClientStateListener; +import net.rubyeye.xmemcached.MemcachedSessionLocator; import net.rubyeye.xmemcached.XMemcachedClient; +import net.rubyeye.xmemcached.XMemcachedClientBuilder; +import net.rubyeye.xmemcached.auth.AuthInfo; +import net.rubyeye.xmemcached.buffer.BufferAllocator; +import net.rubyeye.xmemcached.buffer.SimpleBufferAllocator; import net.rubyeye.xmemcached.command.Command; import net.rubyeye.xmemcached.command.TextCommandFactory; import net.rubyeye.xmemcached.exception.MemcachedException; +import net.rubyeye.xmemcached.impl.ArrayMemcachedSessionLocator; +import net.rubyeye.xmemcached.transcoders.SerializingTranscoder; +import net.rubyeye.xmemcached.transcoders.Transcoder; import net.rubyeye.xmemcached.utils.InetSocketAddressWrapper; /** @@ -186,10 +199,43 @@ public AWSElasticCacheClient(List addrs, * protocol command factory. * @throws IOException */ + @SuppressWarnings("unchecked") public AWSElasticCacheClient(List addrs, long pollConfigIntervalMills, CommandFactory commandFactory) throws IOException { - super(addrs, commandFactory); + this(new ArrayMemcachedSessionLocator(), new SimpleBufferAllocator(), + XMemcachedClientBuilder.getDefaultConfiguration(), + XMemcachedClientBuilder.getDefaultSocketOptions(), + new TextCommandFactory(), new SerializingTranscoder(), + (List) Collections.EMPTY_LIST, + (Map) Collections.EMPTY_MAP, 1, + XMemcachedClient.DEFAULT_CONNECT_TIMEOUT, null, true, addrs, + pollConfigIntervalMills); + + } + + private static Map getAddressMapFromConfigAddrs( + List configAddrs) { + Map m = new HashMap(); + for (InetSocketAddress addr : configAddrs) { + m.put(addr, null); + } + return m; + } + + AWSElasticCacheClient(MemcachedSessionLocator locator, + BufferAllocator allocator, Configuration conf, + Map socketOptions, + CommandFactory commandFactory, Transcoder transcoder, + List stateListeners, + Map map, int poolSize, + long connectTimeout, String name, boolean failureMode, + List configAddrs, long pollConfigIntervalMills) + throws IOException { + super(locator, allocator, conf, socketOptions, commandFactory, + transcoder, getAddressMapFromConfigAddrs(configAddrs), + stateListeners, map, poolSize, connectTimeout, name, + failureMode); if (pollConfigIntervalMills <= 0) { throw new IllegalArgumentException( "Invalid pollConfigIntervalMills value."); @@ -197,7 +243,7 @@ public AWSElasticCacheClient(List addrs, // Use failure mode by default. this.commandFactory = commandFactory; this.setFailureMode(true); - this.configAddrs = addrs; + this.configAddrs = configAddrs; this.configPoller = new ConfigurationPoller(this, pollConfigIntervalMills); // Run at once to get config at startup. @@ -205,8 +251,8 @@ public AWSElasticCacheClient(List addrs, this.configPoller.run(); if (this.currentClusterConfiguration == null) { throw new IllegalStateException( - "Retrieve ElasticCache config from `" + addrs.toString() - + "` failed."); + "Retrieve ElasticCache config from `" + + configAddrs.toString() + "` failed."); } this.configPoller.start(); } diff --git a/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClientBuilder.java b/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClientBuilder.java new file mode 100644 index 000000000..f360f9c99 --- /dev/null +++ b/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClientBuilder.java @@ -0,0 +1,102 @@ +package net.rubyeye.xmemcached.aws; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.List; + +import net.rubyeye.xmemcached.XMemcachedClientBuilder; + +/** + * AWSElasticCacheClient builder. + * + * @author dennis + * + */ +public class AWSElasticCacheClientBuilder extends XMemcachedClientBuilder { + + /** + * Returns pollConfigIntervalMs. + * + * @return + */ + public long getPollConfigIntervalMs() { + return pollConfigIntervalMs; + } + + /** + * Set poll config interval in milliseconds. + * + * @param pollConfigIntervalMs + */ + public void setPollConfigIntervalMs(long pollConfigIntervalMs) { + this.pollConfigIntervalMs = pollConfigIntervalMs; + } + + /** + * Returns initial ElasticCache server addresses. + * + * @return + */ + public List getConfigAddrs() { + return configAddrs; + } + + /** + * Set initial ElasticCache server addresses. + * + * @param configAddrs + */ + public void setConfigAddrs(List configAddrs) { + this.configAddrs = configAddrs; + } + + private List configAddrs; + + private long pollConfigIntervalMs = AWSElasticCacheClient.DEFAULT_POLL_CONFIG_INTERVAL_MS; + + /** + * Create a builder with an initial ElasticCache server. + * + * @param addressList + * @param configAddrs + */ + public AWSElasticCacheClientBuilder(InetSocketAddress addr) { + this(asList(addr)); + } + + private static List asList(InetSocketAddress addr) { + List ret = new ArrayList(); + ret.add(addr); + return ret; + } + + /** + * Create a builder with initial ElasticCache server addresses. + * + * @param addressList + * @param configAddrs + */ + public AWSElasticCacheClientBuilder(List configAddrs) { + super(configAddrs); + this.configAddrs = configAddrs; + } + + /** + * Returns a new instanceof AWSElasticCacheClient. + */ + @Override + public AWSElasticCacheClient build() throws IOException { + + AWSElasticCacheClient memcachedClient = new AWSElasticCacheClient( + this.sessionLocator, this.bufferAllocator, this.configuration, + this.socketOptions, this.commandFactory, this.transcoder, + this.stateListeners, this.authInfoMap, this.connectionPoolSize, + this.connectTimeout, this.name, this.failureMode, configAddrs, + this.pollConfigIntervalMs); + this.configureClient(memcachedClient); + + return memcachedClient; + } + +} diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/AWSElasticCacheClientIT.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/AWSElasticCacheClientIT.java index 9c36d0d15..c1e966776 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/AWSElasticCacheClientIT.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/AWSElasticCacheClientIT.java @@ -5,6 +5,7 @@ import java.util.Properties; import net.rubyeye.xmemcached.aws.AWSElasticCacheClient; +import net.rubyeye.xmemcached.aws.AWSElasticCacheClientBuilder; import net.rubyeye.xmemcached.aws.ClusterConfigration; import net.rubyeye.xmemcached.utils.AddrUtil; @@ -117,6 +118,31 @@ public void testPollConfigAndUsage() throws Exception { } } + @Test + public void testPollConfigAndUsageWithBuilder() throws Exception { + TCPController configServer = new TCPController(); + int version = 10; + configServer.setHandler(new MockHandler(version, serverList)); + configServer.setCodecFactory(new TextLineCodecFactory()); + configServer.bind(new InetSocketAddress(2279)); + + try { + AWSElasticCacheClientBuilder builder = new AWSElasticCacheClientBuilder( + new InetSocketAddress(2279)); + builder.setConnectionPoolSize(2); + builder.setEnableHealSession(false); + AWSElasticCacheClient client = builder.build(); + ClusterConfigration config = client.getCurrentConfig(); + assertEquals(config.getVersion(), version); + assertEquals(addresses.size(), config.getNodeList().size()); + + client.set("aws-cache", 0, "foobar"); + assertEquals("foobar", client.get("aws-cache")); + } finally { + configServer.stop(); + } + } + @Test public void testPollConfigInterval() throws Exception { TCPController cs1 = new TCPController(); From 930c2ee9ce01154fca7a9c71f1fc14ba8b64bf98 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Sun, 12 Mar 2017 22:04:03 +0800 Subject: [PATCH 099/207] (feat) adds string param constructor. --- .../aws/AWSElasticCacheClientBuilder.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClientBuilder.java b/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClientBuilder.java index f360f9c99..4635aa5a0 100644 --- a/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClientBuilder.java +++ b/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClientBuilder.java @@ -6,6 +6,7 @@ import java.util.List; import net.rubyeye.xmemcached.XMemcachedClientBuilder; +import net.rubyeye.xmemcached.utils.AddrUtil; /** * AWSElasticCacheClient builder. @@ -55,11 +56,21 @@ public void setConfigAddrs(List configAddrs) { private long pollConfigIntervalMs = AWSElasticCacheClient.DEFAULT_POLL_CONFIG_INTERVAL_MS; + /** + * Create a builder with an initial ElasticCache server list string in the + * form of "host:port host2:port". + * + * @param serverList + * server list string in the form of "host:port host2:port" + */ + public AWSElasticCacheClientBuilder(String serverList) { + this(AddrUtil.getAddresses(serverList)); + } + /** * Create a builder with an initial ElasticCache server. * - * @param addressList - * @param configAddrs + * @param addr */ public AWSElasticCacheClientBuilder(InetSocketAddress addr) { this(asList(addr)); @@ -74,7 +85,6 @@ private static List asList(InetSocketAddress addr) { /** * Create a builder with initial ElasticCache server addresses. * - * @param addressList * @param configAddrs */ public AWSElasticCacheClientBuilder(List configAddrs) { From d11c0786b99f53c5103cf18df11e8855570be522 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Sun, 12 Mar 2017 22:11:33 +0800 Subject: [PATCH 100/207] [maven-release-plugin] prepare release xmemcached-2.3.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 836e48d0b..4f85a9588 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ 4.0.0 com.googlecode.xmemcached xmemcached - 2.3.1-SNAPSHOT + 2.3.1 xmemcached Extreme performance modern memcached client for java https://github.com/killme2008/xmemcached From 334e9486dcc86d83ac97f46e745a5506a83b5e1e Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Sun, 12 Mar 2017 22:11:41 +0800 Subject: [PATCH 101/207] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4f85a9588..cff7ea215 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ 4.0.0 com.googlecode.xmemcached xmemcached - 2.3.1 + 2.3.2-SNAPSHOT xmemcached Extreme performance modern memcached client for java https://github.com/killme2008/xmemcached From e1b11858898ce7fb32aee74055a842c419363702 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Mon, 13 Mar 2017 08:18:32 +0800 Subject: [PATCH 102/207] (feat) update readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f3697e17b..e501f0f85 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ #News +* [2.3.1](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.1) released, Adds `AWSElasticCacheClientBuilder` to build `AWSElasticCacheClient`. * [2.3.0](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.0) released, suppports [AWS ElasticCache Auto Discovery](http://docs.aws.amazon.com/AmazonElastiCache/latest/UserGuide/AutoDiscovery.html). * [2.2.0](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.2.0) released, highly recommended upgrading. From 7ac789418c7b555cab16021754c2c6d3ba301d38 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Tue, 16 May 2017 10:50:34 +0800 Subject: [PATCH 103/207] Update README.md --- README.md | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index e501f0f85..49b0cae2d 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,27 @@ -[![Build Status](https://travis-ci.org/killme2008/xmemcached.svg?branch=master)](https://travis-ci.org/killme2008/xmemcached) - -#News - -* [2.3.1](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.1) released, Adds `AWSElasticCacheClientBuilder` to build `AWSElasticCacheClient`. -* [2.3.0](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.0) released, suppports [AWS ElasticCache Auto Discovery](http://docs.aws.amazon.com/AmazonElastiCache/latest/UserGuide/AutoDiscovery.html). -* [2.2.0](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.2.0) released, highly recommended upgrading. - -##Introduction - - XMemcached is a high performance, easy to use blocking multithreaded memcached client in java. +[![Build Status](https://travis-ci.org/killme2008/xmemcached.svg?branch=master)](https://travis-ci.org/killme2008/xmemcached) + +## News + +* [2.3.1](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.1) released, Adds `AWSElasticCacheClientBuilder` to build `AWSElasticCacheClient`. +* [2.3.0](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.0) released, suppports [AWS ElasticCache Auto Discovery](http://docs.aws.amazon.com/AmazonElastiCache/latest/UserGuide/AutoDiscovery.html). +* [2.2.0](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.2.0) released, highly recommended upgrading. + +## Introduction + + XMemcached is a high performance, easy to use blocking multithreaded memcached client in java. It's nio based and was carefully turned to get top performance. * [Homepage](http://fnil.net/xmemcached/) * [Wiki](https://github.com/killme2008/xmemcached/wiki) -* [Javadoc](http://fnil.net/docs/xmemcached/index.html) +* [Javadoc](http://fnil.net/docs/xmemcached/index.html) * [ChangeLog](https://github.com/killme2008/xmemcached/blob/master/NOTICE.txt) - -Quick start: - -* [Getting started](https://github.com/killme2008/xmemcached/wiki/Getting%20started) -* [快速入门](https://github.com/killme2008/xmemcached/wiki/%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8) + +Quick start: + +* [Getting started](https://github.com/killme2008/xmemcached/wiki/Getting%20started) +* [快速入门](https://github.com/killme2008/xmemcached/wiki/%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8) ## Contributors @@ -34,9 +34,9 @@ Quick start: * [jovanchohan](https://github.com/jovanchohan) * [profondometer](https://github.com/profondometer) * [machao9email](https://code.google.com/u/100914576372416966057) -* [spudone](https://github.com/spudone) +* [spudone](https://github.com/spudone) * [MikeBily](https://github.com/MikeBily) -##License +## License [Apache License Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html) From bd65736a048627d19068e4584711e10f6e9c50a6 Mon Sep 17 00:00:00 2001 From: Lucas POUZAC Date: Thu, 15 Jun 2017 17:05:41 +0200 Subject: [PATCH 104/207] Add compatibility with Gwhalin Memcached Java Client --- .../impl/ClosedMemcachedTCPSession.java | 24 +--- .../impl/KetamaMemcachedSessionLocator.java | 35 +++++- .../networking/ClosedMemcachedSession.java | 21 ++++ .../networking/MemcachedSession.java | 17 +-- .../test/unittest/MockMemcachedSession.java | 66 +++++++++++ .../xmemcached/test/unittest/MockSession.java | 2 +- ...torGwhalinMemcachedJavaClientUnitTest.java | 103 ++++++++++++++++++ 7 files changed, 223 insertions(+), 45 deletions(-) create mode 100644 src/main/java/net/rubyeye/xmemcached/networking/ClosedMemcachedSession.java create mode 100644 src/test/java/net/rubyeye/xmemcached/test/unittest/MockMemcachedSession.java create mode 100644 src/test/java/net/rubyeye/xmemcached/test/unittest/impl/KetamaMemcachedSessionLocatorGwhalinMemcachedJavaClientUnitTest.java diff --git a/src/main/java/net/rubyeye/xmemcached/impl/ClosedMemcachedTCPSession.java b/src/main/java/net/rubyeye/xmemcached/impl/ClosedMemcachedTCPSession.java index bc8534d00..326451dd4 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/ClosedMemcachedTCPSession.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/ClosedMemcachedTCPSession.java @@ -4,8 +4,7 @@ import java.net.InetSocketAddress; import java.nio.ByteOrder; -import net.rubyeye.xmemcached.buffer.BufferAllocator; -import net.rubyeye.xmemcached.networking.MemcachedSession; +import net.rubyeye.xmemcached.networking.ClosedMemcachedSession; import net.rubyeye.xmemcached.utils.InetSocketAddressWrapper; import com.google.code.yanf4j.core.Handler; @@ -18,7 +17,7 @@ * @author dennis * */ -public class ClosedMemcachedTCPSession implements MemcachedSession { +public class ClosedMemcachedTCPSession implements ClosedMemcachedSession { private InetSocketAddressWrapper inetSocketAddressWrapper; private volatile boolean allowReconnect = true; @@ -28,10 +27,6 @@ public ClosedMemcachedTCPSession( this.inetSocketAddressWrapper = inetSocketAddressWrapper; } - public void destroy() { - - } - public InetSocketAddressWrapper getInetSocketAddressWrapper() { return this.inetSocketAddressWrapper; } @@ -48,17 +43,10 @@ public boolean isAllowReconnect() { return this.allowReconnect; } - public void quit() { - - } - public void setAllowReconnect(boolean allow) { this.allowReconnect = allow; } - public void setBufferAllocator(BufferAllocator allocator) { - - } public void clearAttributes() { @@ -201,14 +189,6 @@ public void setUseBlockingRead(boolean useBlockingRead) { } - public boolean isAuthFailed() { - return false; - } - - public void setAuthFailed(boolean authFailed) { - - } - public void setUseBlockingWrite(boolean useBlockingWrite) { } diff --git a/src/main/java/net/rubyeye/xmemcached/impl/KetamaMemcachedSessionLocator.java b/src/main/java/net/rubyeye/xmemcached/impl/KetamaMemcachedSessionLocator.java index 838ae823d..023e911cb 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/KetamaMemcachedSessionLocator.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/KetamaMemcachedSessionLocator.java @@ -60,32 +60,46 @@ public class KetamaMemcachedSessionLocator extends */ static final int DEFAULT_PORT = 11211; private final boolean cwNginxUpstreamConsistent; + private final boolean gwhalinMemcachedJavaClientCompatibiltyConsistent; public KetamaMemcachedSessionLocator() { this.hashAlg = HashAlgorithm.KETAMA_HASH; this.cwNginxUpstreamConsistent = false; + this.gwhalinMemcachedJavaClientCompatibiltyConsistent = false; } public KetamaMemcachedSessionLocator(boolean cwNginxUpstreamConsistent) { this.hashAlg = HashAlgorithm.KETAMA_HASH; this.cwNginxUpstreamConsistent = cwNginxUpstreamConsistent; + this.gwhalinMemcachedJavaClientCompatibiltyConsistent = false; } public KetamaMemcachedSessionLocator(HashAlgorithm alg) { this.hashAlg = alg; this.cwNginxUpstreamConsistent = false; + this.gwhalinMemcachedJavaClientCompatibiltyConsistent = false; } public KetamaMemcachedSessionLocator(HashAlgorithm alg, boolean cwNginxUpstreamConsistent) { this.hashAlg = alg; this.cwNginxUpstreamConsistent = cwNginxUpstreamConsistent; + this.gwhalinMemcachedJavaClientCompatibiltyConsistent = false; } + public KetamaMemcachedSessionLocator(HashAlgorithm alg, + boolean cwNginxUpstreamConsistent, + boolean gwhalinMemcachedJavaClientCompatibiltyConsistent) { + this.hashAlg = HashAlgorithm.KETAMA_HASH; + this.cwNginxUpstreamConsistent = cwNginxUpstreamConsistent; + this.gwhalinMemcachedJavaClientCompatibiltyConsistent = gwhalinMemcachedJavaClientCompatibiltyConsistent; + } + public KetamaMemcachedSessionLocator(List list, HashAlgorithm alg) { super(); this.hashAlg = alg; this.cwNginxUpstreamConsistent = false; + this.gwhalinMemcachedJavaClientCompatibiltyConsistent = false; this.buildMap(list, alg); } @@ -102,11 +116,20 @@ private final void buildMap(Collection list, HashAlgorithm alg) { sockStr = sockStr + ":" + serverAddress.getPort(); } } else { - if (session instanceof MemcachedTCPSession) { - // Always use the first time resolved address. - sockStr = ((MemcachedTCPSession) session) - .getInetSocketAddressWrapper() - .getRemoteAddressStr(); + if (session instanceof MemcachedSession) { + if (!gwhalinMemcachedJavaClientCompatibiltyConsistent) { + // Always use the first time resolved address. + sockStr = ((MemcachedSession) session) + .getInetSocketAddressWrapper() + .getRemoteAddressStr(); + } else { + sockStr = ((MemcachedSession) session) + .getInetSocketAddressWrapper() + .getInetSocketAddress().getHostName() + ":" + + ((MemcachedSession) session) + .getInetSocketAddressWrapper() + .getInetSocketAddress().getPort(); + } } if (sockStr == null) { sockStr = String.valueOf(session.getRemoteSocketAddress()); @@ -116,7 +139,7 @@ private final void buildMap(Collection list, HashAlgorithm alg) { * Duplicate 160 X weight references */ int numReps = NUM_REPS; - if (session instanceof MemcachedTCPSession) { + if (session instanceof MemcachedSession) { numReps *= ((MemcachedSession) session).getWeight(); } if (alg == HashAlgorithm.KETAMA_HASH) { diff --git a/src/main/java/net/rubyeye/xmemcached/networking/ClosedMemcachedSession.java b/src/main/java/net/rubyeye/xmemcached/networking/ClosedMemcachedSession.java new file mode 100644 index 000000000..f804274fd --- /dev/null +++ b/src/main/java/net/rubyeye/xmemcached/networking/ClosedMemcachedSession.java @@ -0,0 +1,21 @@ +package net.rubyeye.xmemcached.networking; + +import com.google.code.yanf4j.core.Session; + +import net.rubyeye.xmemcached.utils.InetSocketAddressWrapper; + +public interface ClosedMemcachedSession extends Session { + + public void setAllowReconnect(boolean allow); + + public boolean isAllowReconnect(); + + public InetSocketAddressWrapper getInetSocketAddressWrapper(); + + @Deprecated + public int getWeight(); + + @Deprecated + public int getOrder(); + +} diff --git a/src/main/java/net/rubyeye/xmemcached/networking/MemcachedSession.java b/src/main/java/net/rubyeye/xmemcached/networking/MemcachedSession.java index 735f6dfac..dcba13f99 100644 --- a/src/main/java/net/rubyeye/xmemcached/networking/MemcachedSession.java +++ b/src/main/java/net/rubyeye/xmemcached/networking/MemcachedSession.java @@ -23,9 +23,6 @@ package net.rubyeye.xmemcached.networking; import net.rubyeye.xmemcached.buffer.BufferAllocator; -import net.rubyeye.xmemcached.utils.InetSocketAddressWrapper; - -import com.google.code.yanf4j.core.Session; /** * Abstract interface for memcached connection. @@ -33,24 +30,12 @@ * @author dennis * */ -public interface MemcachedSession extends Session { - - public void setAllowReconnect(boolean allow); - - public boolean isAllowReconnect(); +public interface MemcachedSession extends ClosedMemcachedSession { public void setBufferAllocator(BufferAllocator allocator); - public InetSocketAddressWrapper getInetSocketAddressWrapper(); - public void destroy(); - @Deprecated - public int getWeight(); - - @Deprecated - public int getOrder(); - public void quit(); public boolean isAuthFailed(); diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/MockMemcachedSession.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/MockMemcachedSession.java new file mode 100644 index 000000000..cdc8f1326 --- /dev/null +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/MockMemcachedSession.java @@ -0,0 +1,66 @@ +package net.rubyeye.xmemcached.test.unittest; + +import net.rubyeye.xmemcached.buffer.BufferAllocator; +import net.rubyeye.xmemcached.networking.MemcachedSession; +import net.rubyeye.xmemcached.utils.InetSocketAddressWrapper; + +public class MockMemcachedSession extends MockSession implements MemcachedSession { + + + public MockMemcachedSession(int port) { + super(port); + } + + + public void setAllowReconnect(boolean allow) { + // TODO Auto-generated method stub + + } + + public boolean isAllowReconnect() { + // TODO Auto-generated method stub + return false; + } + + public void setBufferAllocator(BufferAllocator allocator) { + // TODO Auto-generated method stub + + } + + public InetSocketAddressWrapper getInetSocketAddressWrapper() { + InetSocketAddressWrapper inetSocketAddressWrapper = new InetSocketAddressWrapper(getRemoteSocketAddress(), 1, 1, null); + inetSocketAddressWrapper.setRemoteAddressStr("localhost/127.0.0.1:" + this.port); + return inetSocketAddressWrapper; + } + + public void destroy() { + // TODO Auto-generated method stub + + } + + public int getWeight() { + // TODO Auto-generated method stub + return 1; + } + + public int getOrder() { + // TODO Auto-generated method stub + return 0; + } + + public void quit() { + // TODO Auto-generated method stub + + } + + public boolean isAuthFailed() { + // TODO Auto-generated method stub + return false; + } + + public void setAuthFailed(boolean authFailed) { + // TODO Auto-generated method stub + + } + +} diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/MockSession.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/MockSession.java index c81df274b..9e7182f63 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/MockSession.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/MockSession.java @@ -13,7 +13,7 @@ public class MockSession implements Session { private boolean closed = false; - private final int port; + protected final int port; public MockSession(int port) { this.port = port; diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/KetamaMemcachedSessionLocatorGwhalinMemcachedJavaClientUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/KetamaMemcachedSessionLocatorGwhalinMemcachedJavaClientUnitTest.java new file mode 100644 index 000000000..4cd733992 --- /dev/null +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/KetamaMemcachedSessionLocatorGwhalinMemcachedJavaClientUnitTest.java @@ -0,0 +1,103 @@ +package net.rubyeye.xmemcached.test.unittest.impl; + +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.List; + +import net.rubyeye.xmemcached.HashAlgorithm; +import net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator; +import net.rubyeye.xmemcached.test.unittest.MockMemcachedSession; + +import org.junit.Before; +import org.junit.Test; + +import com.google.code.yanf4j.core.Session; + +public class KetamaMemcachedSessionLocatorGwhalinMemcachedJavaClientUnitTest extends + AbstractMemcachedSessionLocatorUnitTest { + + @Before + public void setUp() { + this.locator = new KetamaMemcachedSessionLocator(HashAlgorithm.KETAMA_HASH, false, true); + } + + @Test + public void testGetSessionByKey_MoreSessions() { + MockMemcachedSession session1 = new MockMemcachedSession(8080); + MockMemcachedSession session2 = new MockMemcachedSession(8081); + MockMemcachedSession session3 = new MockMemcachedSession(8082); + System.err.print(session1.getInetSocketAddressWrapper().getRemoteAddressStr()); + + List list = new ArrayList(); + list.add(session1); + list.add(session2); + list.add(session3); + this.locator.updateSessions(list); + + assertSame(session2, this.locator.getSessionByKey("a1")); + assertSame(session3, this.locator.getSessionByKey("a2")); + assertSame(session1, this.locator.getSessionByKey("a3")); + + assertSame(session2, this.locator.getSessionByKey("a1")); + assertSame(session3, this.locator.getSessionByKey("a2")); + assertSame(session1, this.locator.getSessionByKey("a3")); + + assertSame(session2, this.locator.getSessionByKey("a1")); + assertSame(session3, this.locator.getSessionByKey("a2")); + assertSame(session1, this.locator.getSessionByKey("a3")); + + } + + @Test + public void testGetSessionByKey_MoreSessions_OneClosed() { + MockMemcachedSession session1 = new MockMemcachedSession(8080); + MockMemcachedSession session2 = new MockMemcachedSession(8081); + session1.close(); + MockMemcachedSession session3 = new MockMemcachedSession(8082); + List list = new ArrayList(); + list.add(session1); + list.add(session2); + list.add(session3); + this.locator.updateSessions(list); + + assertSame(session2, this.locator.getSessionByKey("a1")); + assertSame(session3, this.locator.getSessionByKey("a2")); + assertSame(session2, this.locator.getSessionByKey("a3")); + + assertSame(session2, this.locator.getSessionByKey("a1")); + assertSame(session3, this.locator.getSessionByKey("a2")); + assertSame(session2, this.locator.getSessionByKey("a3")); + + assertSame(session2, this.locator.getSessionByKey("a1")); + assertSame(session3, this.locator.getSessionByKey("a2")); + assertSame(session2, this.locator.getSessionByKey("a3")); + + } + + @Test + public void testGetSessionByKey_MoreSessions_OneClosed_FailureMode() { + this.locator.setFailureMode(true); + MockMemcachedSession session1 = new MockMemcachedSession(8080); + MockMemcachedSession session2 = new MockMemcachedSession(8081); + session1.close(); + MockMemcachedSession session3 = new MockMemcachedSession(8082); + List list = new ArrayList(); + list.add(session1); + list.add(session2); + list.add(session3); + this.locator.updateSessions(list); + assertSame(session2, this.locator.getSessionByKey("a1")); + assertSame(session3, this.locator.getSessionByKey("a2")); + assertSame(session1, this.locator.getSessionByKey("a3")); + + assertSame(session2, this.locator.getSessionByKey("a1")); + assertSame(session3, this.locator.getSessionByKey("a2")); + assertSame(session1, this.locator.getSessionByKey("a3")); + + assertSame(session2, this.locator.getSessionByKey("a1")); + assertSame(session3, this.locator.getSessionByKey("a2")); + assertSame(session1, this.locator.getSessionByKey("a3")); + } + +} From 0c836cb01e87350b9de636a2cac794ea3454a023 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Mon, 17 Jul 2017 10:51:42 +0800 Subject: [PATCH 105/207] (fix) stop ConfigurationPoller when shutdown client, close #61 --- .../net/rubyeye/xmemcached/XMemcachedClient.java | 8 ++++++++ .../xmemcached/aws/AWSElasticCacheClient.java | 12 ++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java index 20f8aee21..b5cad6433 100644 --- a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java +++ b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java @@ -2417,6 +2417,13 @@ public Map> getStats(long timeout) throws MemcachedException, InterruptedException, TimeoutException { return this.getStatsByItem(null, timeout); } + + /** + * For subclass override. + */ + protected void shutdown0(){ + + } /* * (non-Javadoc) @@ -2427,6 +2434,7 @@ public final void shutdown() throws IOException { if (this.shutdown) { return; } + this.shutdown0(); this.shutdown = true; this.connector.shuttingDown(); this.connector.quitAllSessions(); diff --git a/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java b/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java index a97e978d5..913d8ec97 100644 --- a/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java +++ b/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java @@ -291,6 +291,18 @@ public ClusterConfigration getConfig(String key) throws MemcachedException, return AWSUtils.parseConfiguration(result); } + @Override + protected void shutdown0() { + super.shutdown0(); + if (this.configPoller != null) { + try { + this.configPoller.stop(); + } catch (Exception e) { + // ignore + } + } + } + /** * Get the current using configuration in memory. * From c1c60496f58d34cbc33843da46d6e02eba87555b Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Mon, 17 Jul 2017 10:56:09 +0800 Subject: [PATCH 106/207] (fix) Respect xmemcached.shutdown.hook.enable in controller, close #57 --- .../yanf4j/core/impl/AbstractController.java | 29 +++++++++++-------- .../rubyeye/xmemcached/XMemcachedClient.java | 14 ++------- .../rubyeye/xmemcached/utils/AddrUtil.java | 10 +++++++ 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/google/code/yanf4j/core/impl/AbstractController.java b/src/main/java/com/google/code/yanf4j/core/impl/AbstractController.java index ea763d19f..49b911ade 100644 --- a/src/main/java/com/google/code/yanf4j/core/impl/AbstractController.java +++ b/src/main/java/com/google/code/yanf4j/core/impl/AbstractController.java @@ -34,6 +34,8 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ThreadPoolExecutor; +import net.rubyeye.xmemcached.utils.AddrUtil; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -358,18 +360,20 @@ public synchronized void start() throws IOException { startStatistics(); start0(); notifyStarted(); - shutdownHookThread = new Thread() { - @Override - public void run() { - try { - isHutdownHookCalled = true; - AbstractController.this.stop(); - } catch (IOException e) { - log.error("Stop controller fail", e); + if (AddrUtil.isEnableShutDownHook()) { + shutdownHookThread = new Thread() { + @Override + public void run() { + try { + isHutdownHookCalled = true; + AbstractController.this.stop(); + } catch (IOException e) { + log.error("Stop controller fail", e); + } } - } - }; - Runtime.getRuntime().addShutdownHook(shutdownHookThread); + }; + Runtime.getRuntime().addShutdownHook(shutdownHookThread); + } log.info("The Controller started at " + localSocketAddress + " ..."); } @@ -475,7 +479,8 @@ public void stop() throws IOException { notifyStopped(); clearStateListeners(); stop0(); - if (!isHutdownHookCalled) { + if (AddrUtil.isEnableShutDownHook() && shutdownHookThread != null + && !isHutdownHookCalled) { Runtime.getRuntime().removeShutdownHook(shutdownHookThread); } log.info("Controller has been stopped."); diff --git a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java index b5cad6433..2cf2799fa 100644 --- a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java +++ b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java @@ -111,16 +111,6 @@ public class XMemcachedClient implements XMemcachedClientMBean, MemcachedClient private final CopyOnWriteArrayList stateListenerAdapters = new CopyOnWriteArrayList(); private Thread shutdownHookThread; - /** - * System property to control shutdown hook, issue #44 - * - * @since 2.0.1 - */ - private boolean isEnableShutDownHook() { - return Boolean.valueOf(System.getProperty( - "xmemcached.shutdown.hook.enable", "false")); - } - private volatile boolean isHutdownHookCalled = false; // key provider for pre-processing keys before sending them to memcached // added by dennis,2012-07-14 @@ -679,7 +669,7 @@ private final void startConnector() throws IOException { this.shutdown = false; this.connector.start(); this.memcachedHandler.start(); - if (isEnableShutDownHook()) { + if (AddrUtil.isEnableShutDownHook()) { this.shutdownHookThread = new Thread() { @Override public void run() { @@ -2441,7 +2431,7 @@ public final void shutdown() throws IOException { this.connector.stop(); this.memcachedHandler.stop(); XMemcachedMbeanServer.getInstance().shutdown(); - if (isEnableShutDownHook() && !this.isHutdownHookCalled) { + if (AddrUtil.isEnableShutDownHook() && !this.isHutdownHookCalled) { try { Runtime.getRuntime() .removeShutdownHook(this.shutdownHookThread); diff --git a/src/main/java/net/rubyeye/xmemcached/utils/AddrUtil.java b/src/main/java/net/rubyeye/xmemcached/utils/AddrUtil.java index ae22949bd..a9881b0a5 100644 --- a/src/main/java/net/rubyeye/xmemcached/utils/AddrUtil.java +++ b/src/main/java/net/rubyeye/xmemcached/utils/AddrUtil.java @@ -148,4 +148,14 @@ public static InetSocketAddress getOneAddress(String server) { String portNum = server.substring(finalColon + 1).trim(); return new InetSocketAddress(hostPart, Integer.parseInt(portNum)); } + + /** + * System property to control shutdown hook, issue #44 + * + * @since 2.0.1 + */ + public static boolean isEnableShutDownHook() { + return Boolean.valueOf(System.getProperty( + "xmemcached.shutdown.hook.enable", "false")); + } } From de2687e928fe80b51196854cf7c27c6e6c9438c8 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Mon, 17 Jul 2017 11:08:49 +0800 Subject: [PATCH 107/207] (fix) remove openjdk6 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ea2fb1e61..23a68ce44 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: java jdk: - oraclejdk8 - oraclejdk7 - - openjdk6 + - oraclejdk6 services: - memcached script: From d54bea225f233652c08ee776372c566b6b01e844 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Mon, 17 Jul 2017 11:16:38 +0800 Subject: [PATCH 108/207] (fix) no oraclejdk6 --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 23a68ce44..9d31553f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ language: java jdk: - oraclejdk8 - oraclejdk7 - - oraclejdk6 services: - memcached script: From e5720bd35ab8a5f2d9569dfb39affff0bade657b Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Tue, 18 Jul 2017 11:00:10 +0800 Subject: [PATCH 109/207] [maven-release-plugin] prepare release xmemcached-2.3.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index cff7ea215..2612e5773 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ 4.0.0 com.googlecode.xmemcached xmemcached - 2.3.2-SNAPSHOT + 2.3.2 xmemcached Extreme performance modern memcached client for java https://github.com/killme2008/xmemcached From 9c5050e559c44330d0816366673dd5e810e48f3e Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Tue, 18 Jul 2017 11:00:18 +0800 Subject: [PATCH 110/207] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2612e5773..e8c5466d1 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ 4.0.0 com.googlecode.xmemcached xmemcached - 2.3.2 + 2.3.3-SNAPSHOT xmemcached Extreme performance modern memcached client for java https://github.com/killme2008/xmemcached From ec932c532a94bc0f631f56ac0a9bb7b582f3003f Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Tue, 18 Jul 2017 11:26:10 +0800 Subject: [PATCH 111/207] (feat) release 2.3.2 --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 49b0cae2d..ce73a44b3 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ [![Build Status](https://travis-ci.org/killme2008/xmemcached.svg?branch=master)](https://travis-ci.org/killme2008/xmemcached) ## News - + +* [2.3.2](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.2) released, some fixes and add compatibility for `KetamaMemcachedSessionLocator` with Gwhalin Memcached Java Client. * [2.3.1](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.1) released, Adds `AWSElasticCacheClientBuilder` to build `AWSElasticCacheClient`. * [2.3.0](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.0) released, suppports [AWS ElasticCache Auto Discovery](http://docs.aws.amazon.com/AmazonElastiCache/latest/UserGuide/AutoDiscovery.html). -* [2.2.0](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.2.0) released, highly recommended upgrading. ## Introduction @@ -35,7 +35,8 @@ Quick start: * [profondometer](https://github.com/profondometer) * [machao9email](https://code.google.com/u/100914576372416966057) * [spudone](https://github.com/spudone) -* [MikeBily](https://github.com/MikeBily) +* [MikeBily](https://github.com/MikeBily) +* [Lucas Pouzac](https://github.com/lucaspouzac) ## License From a19ab3eaf749f320186e80587d26d1d5bf9627b5 Mon Sep 17 00:00:00 2001 From: IluckySi Date: Tue, 26 Sep 2017 21:30:32 +0800 Subject: [PATCH 112/207] Remove duplicate MemcachedException on fetch0 method --- src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java index 2cf2799fa..20676bbba 100644 --- a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java +++ b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java @@ -638,7 +638,7 @@ protected void connect( private final Object fetch0(final String key, final byte[] keyBytes, final CommandType cmdType, final long timeout, Transcoder transcoder) throws InterruptedException, - TimeoutException, MemcachedException, MemcachedException { + TimeoutException, MemcachedException { final Command command = this.commandFactory.createGetCommand(key, keyBytes, cmdType, this.transcoder); this.latchWait(command, timeout, this.sendCommand(command)); From 97e57ea3b7ab93afd730216fc2e4861f7c2a690e Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Tue, 26 Sep 2017 21:54:16 +0800 Subject: [PATCH 113/207] add contributor. --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ce73a44b3..277754e22 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ [![Build Status](https://travis-ci.org/killme2008/xmemcached.svg?branch=master)](https://travis-ci.org/killme2008/xmemcached) ## News - + * [2.3.2](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.2) released, some fixes and add compatibility for `KetamaMemcachedSessionLocator` with Gwhalin Memcached Java Client. * [2.3.1](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.1) released, Adds `AWSElasticCacheClientBuilder` to build `AWSElasticCacheClient`. * [2.3.0](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.0) released, suppports [AWS ElasticCache Auto Discovery](http://docs.aws.amazon.com/AmazonElastiCache/latest/UserGuide/AutoDiscovery.html). @@ -35,8 +35,9 @@ Quick start: * [profondometer](https://github.com/profondometer) * [machao9email](https://code.google.com/u/100914576372416966057) * [spudone](https://github.com/spudone) -* [MikeBily](https://github.com/MikeBily) +* [MikeBily](https://github.com/MikeBily) * [Lucas Pouzac](https://github.com/lucaspouzac) +* [IluckySi](https://github.com/IluckySi) ## License From 72bbdc981584d1fe9602eac1ec04ba3a4e431393 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Wed, 25 Oct 2017 11:52:38 +0800 Subject: [PATCH 114/207] (fix) busy CPU when checking session timeout in postSelect --- .../google/code/yanf4j/nio/impl/Reactor.java | 72 +++++++++++-------- 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/google/code/yanf4j/nio/impl/Reactor.java b/src/main/java/com/google/code/yanf4j/nio/impl/Reactor.java index 670d530fa..c345cfdd2 100644 --- a/src/main/java/com/google/code/yanf4j/nio/impl/Reactor.java +++ b/src/main/java/com/google/code/yanf4j/nio/impl/Reactor.java @@ -40,10 +40,11 @@ public final class Reactor extends Thread { /** * JVM bug threshold */ - public static final int JVMBUG_THRESHHOLD = Integer.getInteger( - "com.googlecode.yanf4j.nio.JVMBUG_THRESHHOLD", 128); + public static final int JVMBUG_THRESHHOLD = Integer + .getInteger("com.googlecode.yanf4j.nio.JVMBUG_THRESHHOLD", 128); public static final int JVMBUG_THRESHHOLD2 = JVMBUG_THRESHHOLD * 2; - public static final int JVMBUG_THRESHHOLD1 = (JVMBUG_THRESHHOLD2 + JVMBUG_THRESHHOLD) / 2; + public static final int JVMBUG_THRESHHOLD1 = (JVMBUG_THRESHHOLD2 + + JVMBUG_THRESHHOLD) / 2; public static final int DEFAULT_WAIT = 1000; private static final Logger log = LoggerFactory.getLogger("remoting"); @@ -111,6 +112,8 @@ public RegisterEvent(Session session, EventType eventType) { private long nextTimeout = 0; + private long lastCheckTimestamp = 0L; + Reactor(SelectorManager selectorManager, Configuration configuration, int index) throws IOException { super(); @@ -218,17 +221,18 @@ private boolean lookJVMBug(long before, int selected, long wait) gate.lock(); try { lastJVMBug = now; - log.warn("JVM bug occured at " - + new Date(lastJVMBug) + log.warn("JVM bug occured at " + new Date(lastJVMBug) + ",http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6403933,reactIndex=" + reactorIndex); if (jvmBug1) { - log.debug("seeing JVM BUG(s) - recreating selector,reactIndex=" - + reactorIndex); + log.debug( + "seeing JVM BUG(s) - recreating selector,reactIndex=" + + reactorIndex); } else { jvmBug1 = true; - log.info("seeing JVM BUG(s) - recreating selector,reactIndex=" - + reactorIndex); + log.info( + "seeing JVM BUG(s) - recreating selector,reactIndex=" + + reactorIndex); } seeing = true; final Selector new_selector = SystemUtils.openSelector(); @@ -256,12 +260,14 @@ private boolean lookJVMBug(long before, int selected, long wait) } else if (jvmBug.get() == JVMBUG_THRESHHOLD || jvmBug.get() == JVMBUG_THRESHHOLD1) { if (jvmBug0) { - log.debug("seeing JVM BUG(s) - cancelling interestOps==0,reactIndex=" - + reactorIndex); + log.debug( + "seeing JVM BUG(s) - cancelling interestOps==0,reactIndex=" + + reactorIndex); } else { jvmBug0 = true; - log.info("seeing JVM BUG(s) - cancelling interestOps==0,reactIndex=" - + reactorIndex); + log.info( + "seeing JVM BUG(s) - cancelling interestOps==0,reactIndex=" + + reactorIndex); } gate.lock(); seeing = true; @@ -305,8 +311,8 @@ public final void dispatchEvent(Set selectedKeySet) { controller.onAccept(key); continue; } - if (key.isValid() - && (key.readyOps() & SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE) { + if (key.isValid() && (key.readyOps() + & SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE) { // Remove write interest key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE); controller.onWrite(key); @@ -314,20 +320,20 @@ public final void dispatchEvent(Set selectedKeySet) { skipOpRead = true; } } - if (!skipOpRead - && key.isValid() - && (key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) { + if (!skipOpRead && key.isValid() && (key.readyOps() + & SelectionKey.OP_READ) == SelectionKey.OP_READ) { key.interestOps(key.interestOps() & ~SelectionKey.OP_READ); if (!controller.getStatistics().isReceiveOverFlow()) { // Remove read interest controller.onRead(key); } else { - key.interestOps(key.interestOps() - | SelectionKey.OP_READ); + key.interestOps( + key.interestOps() | SelectionKey.OP_READ); } } - if ((key.readyOps() & SelectionKey.OP_CONNECT) == SelectionKey.OP_CONNECT) { + if ((key.readyOps() + & SelectionKey.OP_CONNECT) == SelectionKey.OP_CONNECT) { controller.onConnect(key); } @@ -383,8 +389,7 @@ private final long checkSessionTimeout() { if (configuration.getCheckSessionTimeoutInterval() > 0) { gate.lock(); try { - if (selectTries * 1000 >= configuration - .getCheckSessionTimeoutInterval()) { + if (isNeedCheckSessionIdleTimeout()) { nextTimeout = configuration .getCheckSessionTimeoutInterval(); for (SelectionKey key : selector.keys()) { @@ -396,6 +401,7 @@ private final long checkSessionTimeout() { } } selectTries = 0; + lastCheckTimestamp = System.currentTimeMillis(); } } finally { gate.unlock(); @@ -404,6 +410,14 @@ private final long checkSessionTimeout() { return nextTimeout; } + private boolean isNeedCheckSessionIdleTimeout() { + return selectTries * 1000 >= configuration + .getCheckSessionTimeoutInterval() + || System.currentTimeMillis() + - this.lastCheckTimestamp >= configuration + .getCheckSessionTimeoutInterval(); + } + private final Session getSessionFromAttchment(SelectionKey key) { if (key.attachment() instanceof Session) { return (Session) key.attachment(); @@ -462,13 +476,15 @@ public final void postSelect(Set selectedKeys, Set allKeys) { if (controller.getSessionTimeout() > 0 || controller.getSessionIdleTimeout() > 0) { - for (SelectionKey key : allKeys) { - - if (!selectedKeys.contains(key)) { - if (key.attachment() != null) { - checkExpiredIdle(key, getSessionFromAttchment(key)); + if (isNeedCheckSessionIdleTimeout()) { + for (SelectionKey key : allKeys) { + if (!selectedKeys.contains(key)) { + if (key.attachment() != null) { + checkExpiredIdle(key, getSessionFromAttchment(key)); + } } } + lastCheckTimestamp = System.currentTimeMillis(); } } } From 38ab72f26d513e6b35bc10529c0562238b2920f7 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Wed, 25 Oct 2017 17:43:37 +0800 Subject: [PATCH 115/207] (feat) use switch instead of if/else --- .../yanf4j/nio/impl/AbstractNioSession.java | 82 +++++++++---------- .../google/code/yanf4j/nio/impl/Reactor.java | 17 ++-- 2 files changed, 50 insertions(+), 49 deletions(-) diff --git a/src/main/java/com/google/code/yanf4j/nio/impl/AbstractNioSession.java b/src/main/java/com/google/code/yanf4j/nio/impl/AbstractNioSession.java index 69ec6283c..48138d21b 100644 --- a/src/main/java/com/google/code/yanf4j/nio/impl/AbstractNioSession.java +++ b/src/main/java/com/google/code/yanf4j/nio/impl/AbstractNioSession.java @@ -25,8 +25,9 @@ * @author dennis * */ -public abstract class AbstractNioSession extends AbstractSession implements - NioSession { +public abstract class AbstractNioSession extends AbstractSession + implements + NioSession { public SelectableChannel channel() { return selectableChannel; @@ -47,8 +48,8 @@ public final void enableRead(Selector selector) { interestRead(key); } else { try { - selectableChannel - .register(selector, SelectionKey.OP_READ, this); + selectableChannel.register(selector, SelectionKey.OP_READ, + this); } catch (ClosedChannelException e) { // ignore } catch (CancelledKeyException e) { @@ -96,7 +97,8 @@ protected void onWrite(SelectionKey key) { isLockedByMe = true; WriteMessage currentMessage = null; - final long maxWritten = readBuffer.capacity() + readBuffer.capacity() >>> 1; + final long maxWritten = readBuffer.capacity() + + readBuffer.capacity() >>> 1; try { long written = 0; while (this.currentMessage.get() != null) { @@ -110,8 +112,7 @@ protected void onWrite(SelectionKey key) { if (written < maxWritten) { writeResult = writeToChannel(currentMessage); written += this.currentMessage.get().getWriteBuffer() - .remaining() - - before; + .remaining() - before; } else { // wait for next time to write } @@ -125,13 +126,12 @@ protected void onWrite(SelectionKey key) { isLockedByMe = false; writeLock.unlock(); } - // get next message + // get next message WriteMessage nextMessage = writeQueue.peek(); if (nextMessage != null && writeLock.tryLock()) { isLockedByMe = true; - if (!writeQueue.isEmpty() - && this.currentMessage.compareAndSet(null, - nextMessage)) { + if (!writeQueue.isEmpty() && this.currentMessage + .compareAndSet(null, nextMessage)) { writeQueue.remove(); } continue; @@ -145,7 +145,7 @@ protected void onWrite(SelectionKey key) { isLockedByMe = false; writeLock.unlock(); } - // register OP_WRITE event + // register OP_WRITE event selectorManager.registerSession(this, EventType.ENABLE_WRITE); break; @@ -175,8 +175,8 @@ public final void enableWrite(Selector selector) { interestWrite(key); } else { try { - selectableChannel.register(selector, - SelectionKey.OP_WRITE, this); + selectableChannel.register(selector, SelectionKey.OP_WRITE, + this); } catch (ClosedChannelException e) { // ignore } catch (CancelledKeyException e) { @@ -233,9 +233,7 @@ public void writeFromUserCode(WriteMessage message) { if (schduleWriteMessage(message)) { return; } - // 到这里,当前线程一定是IO线程 onWrite(null); - } protected boolean schduleWriteMessage(WriteMessage writeMessage) { @@ -311,8 +309,8 @@ protected final long doRealWrite(SelectableChannel channel, IoBuffer buffer) if (log.isDebugEnabled()) { StringBuffer bufMsg = new StringBuffer("send buffers:\n[\n"); final ByteBuffer buff = buffer.buf(); - bufMsg.append(" buffer:position=").append(buff.position()).append( - ",limit=").append(buff.limit()).append(",capacity=") + bufMsg.append(" buffer:position=").append(buff.position()) + .append(",limit=").append(buff.limit()).append(",capacity=") .append(buff.capacity()).append("\n"); bufMsg.append("]"); @@ -331,30 +329,30 @@ public final void onEvent(EventType event, Selector selector) { SelectionKey key = selectableChannel.keyFor(selector); switch (event) { - case EXPIRED: - onExpired(); - break; - case WRITEABLE: - onWrite(key); - break; - case READABLE: - onRead(key); - break; - case ENABLE_WRITE: - enableWrite(selector); - break; - case ENABLE_READ: - enableRead(selector); - break; - case IDLE: - onIdle(); - break; - case CONNECTED: - onConnected(); - break; - default: - log.error("Unknown event:" + event.name()); - break; + case EXPIRED : + onExpired(); + break; + case WRITEABLE : + onWrite(key); + break; + case READABLE : + onRead(key); + break; + case ENABLE_WRITE : + enableWrite(selector); + break; + case ENABLE_READ : + enableRead(selector); + break; + case IDLE : + onIdle(); + break; + case CONNECTED : + onConnected(); + break; + default : + log.error("Unknown event:" + event.name()); + break; } } } diff --git a/src/main/java/com/google/code/yanf4j/nio/impl/Reactor.java b/src/main/java/com/google/code/yanf4j/nio/impl/Reactor.java index c345cfdd2..6be3986db 100644 --- a/src/main/java/com/google/code/yanf4j/nio/impl/Reactor.java +++ b/src/main/java/com/google/code/yanf4j/nio/impl/Reactor.java @@ -159,7 +159,7 @@ public void run() { lookJVMBug(before, selected, wait); } selectTries++; - // check tmeout and idle + // check timeout and idle nextTimeout = checkSessionTimeout(); continue; } else { @@ -463,12 +463,15 @@ private final void dispatchSessionEvent(Session session, EventType event) { if (session.isClosed() && event != EventType.UNREGISTER) { return; } - if (EventType.REGISTER.equals(event)) { - controller.registerSession(session); - } else if (EventType.UNREGISTER.equals(event)) { - controller.unregisterSession(session); - } else { - ((NioSession) session).onEvent(event, selector); + switch (event) { + case REGISTER : + controller.registerSession(session); + break; + case UNREGISTER : + controller.unregisterSession(session); + break; + default : + ((NioSession) session).onEvent(event, selector); } } From 635e9214b7c59ddd58aa01023ec458989cbc5e32 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Wed, 25 Oct 2017 17:45:58 +0800 Subject: [PATCH 116/207] (fix) forgot break --- src/main/java/com/google/code/yanf4j/nio/impl/Reactor.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/google/code/yanf4j/nio/impl/Reactor.java b/src/main/java/com/google/code/yanf4j/nio/impl/Reactor.java index 6be3986db..e67c561e7 100644 --- a/src/main/java/com/google/code/yanf4j/nio/impl/Reactor.java +++ b/src/main/java/com/google/code/yanf4j/nio/impl/Reactor.java @@ -472,6 +472,7 @@ private final void dispatchSessionEvent(Session session, EventType event) { break; default : ((NioSession) session).onEvent(event, selector); + break; } } From 62a6d130a5ec25dbe8f054b0c469bb727616fa40 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Wed, 25 Oct 2017 17:53:33 +0800 Subject: [PATCH 117/207] (fix) remove oraclejdk7 and use openjdk7 for travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9d31553f1..667111779 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: java jdk: - oraclejdk8 - - oraclejdk7 + - openjdk7 services: - memcached script: From cb356f63c3f69c49f6092961d79a2865534894ba Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Wed, 25 Oct 2017 18:53:05 +0800 Subject: [PATCH 118/207] (feat) use docker-compose to setup test environment. --- Dockerfile | 3 ++ README.md | 113 +++++++++++++++++++++++++++------------------ docker-compose.yml | 8 ++++ 3 files changed, 80 insertions(+), 44 deletions(-) create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..f16d9b06f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,3 @@ +FROM dexterbt1/kestrel +WORKDIR /usr/local/kestrel/current +CMD ["java","-jar","kestrel_2.9.2-2.4.2-SNAPSHOT.jar","-f","config/development.scala"] diff --git a/README.md b/README.md index 277754e22..0931574e0 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,69 @@ -[![Build Status](https://travis-ci.org/killme2008/xmemcached.svg?branch=master)](https://travis-ci.org/killme2008/xmemcached) - -## News - -* [2.3.2](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.2) released, some fixes and add compatibility for `KetamaMemcachedSessionLocator` with Gwhalin Memcached Java Client. -* [2.3.1](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.1) released, Adds `AWSElasticCacheClientBuilder` to build `AWSElasticCacheClient`. -* [2.3.0](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.0) released, suppports [AWS ElasticCache Auto Discovery](http://docs.aws.amazon.com/AmazonElastiCache/latest/UserGuide/AutoDiscovery.html). - -## Introduction - - XMemcached is a high performance, easy to use blocking multithreaded memcached client in java. - - It's nio based and was carefully turned to get top performance. - -* [Homepage](http://fnil.net/xmemcached/) -* [Wiki](https://github.com/killme2008/xmemcached/wiki) -* [Javadoc](http://fnil.net/docs/xmemcached/index.html) -* [ChangeLog](https://github.com/killme2008/xmemcached/blob/master/NOTICE.txt) - - -Quick start: - -* [Getting started](https://github.com/killme2008/xmemcached/wiki/Getting%20started) -* [快速入门](https://github.com/killme2008/xmemcached/wiki/%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8) - -## Contributors - -* [cnscud](https://code.google.com/u/cnscud/) -* [wolfg1969](https://code.google.com/u/wolfg1969/) -* [vadimp](https://github.com/vadimp) -* [ilkinulas](https://github.com/ilkinulas) -* [aravind](https://github.com/aravind) -* [bmahe](https://github.com/bmahe) -* [jovanchohan](https://github.com/jovanchohan) -* [profondometer](https://github.com/profondometer) -* [machao9email](https://code.google.com/u/100914576372416966057) -* [spudone](https://github.com/spudone) -* [MikeBily](https://github.com/MikeBily) -* [Lucas Pouzac](https://github.com/lucaspouzac) -* [IluckySi](https://github.com/IluckySi) - -## License - -[Apache License Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html) +[![Build Status](https://travis-ci.org/killme2008/xmemcached.svg?branch=master)](https://travis-ci.org/killme2008/xmemcached) + +## News + +* [2.3.2](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.2) released, some fixes and add compatibility for `KetamaMemcachedSessionLocator` with Gwhalin Memcached Java Client. +* [2.3.1](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.1) released, Adds `AWSElasticCacheClientBuilder` to build `AWSElasticCacheClient`. +* [2.3.0](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.0) released, suppports [AWS ElasticCache Auto Discovery](http://docs.aws.amazon.com/AmazonElastiCache/latest/UserGuide/AutoDiscovery.html). + +## Introduction + + XMemcached is a high performance, easy to use blocking multithreaded memcached client in java. + + It's nio based and was carefully turned to get top performance. + +* [Homepage](http://fnil.net/xmemcached/) +* [Wiki](https://github.com/killme2008/xmemcached/wiki) +* [Javadoc](http://fnil.net/docs/xmemcached/index.html) +* [ChangeLog](https://github.com/killme2008/xmemcached/blob/master/NOTICE.txt) + + +Quick start: + +* [Getting started](https://github.com/killme2008/xmemcached/wiki/Getting%20started) +* [快速入门](https://github.com/killme2008/xmemcached/wiki/%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8) + +## Contribute + +[Fork](https://github.com/killme2008/xmemcached#fork-destination-box) the source code and checkout it to your local machine.Make changes and create a pull request. + +Use [docker](https://docs.docker.com/engine/installation/) and [docker-compose](https://docs.docker.com/compose/gettingstarted/) to setup test environment: + +```sh +$ cd xmemcached +$ docker-compose up +``` + +Run unit tests: + +```sh +$ mvn test +``` + +Run intergration test: + +```sh +$ mvn integration-test +``` + +Thanks to all contributors, you make xmemcached better. + +## Contributors + +* [cnscud](https://code.google.com/u/cnscud/) +* [wolfg1969](https://code.google.com/u/wolfg1969/) +* [vadimp](https://github.com/vadimp) +* [ilkinulas](https://github.com/ilkinulas) +* [aravind](https://github.com/aravind) +* [bmahe](https://github.com/bmahe) +* [jovanchohan](https://github.com/jovanchohan) +* [profondometer](https://github.com/profondometer) +* [machao9email](https://code.google.com/u/100914576372416966057) +* [spudone](https://github.com/spudone) +* [MikeBily](https://github.com/MikeBily) +* [Lucas Pouzac](https://github.com/lucaspouzac) +* [IluckySi](https://github.com/IluckySi) + +## License + +[Apache License Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html) diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..50a73211b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,8 @@ +version: '3' +services: + kestrel: + build: . + ports: + - "22133:22133" + memcached: + image: "memcached" From f476ebb436cf737b7b813acf5c3142cbd4d1dbad Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Wed, 25 Oct 2017 19:40:40 +0800 Subject: [PATCH 119/207] [maven-release-plugin] prepare release xmemcached-2.4.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e8c5466d1..c800626ed 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ 4.0.0 com.googlecode.xmemcached xmemcached - 2.3.3-SNAPSHOT + 2.4.0 xmemcached Extreme performance modern memcached client for java https://github.com/killme2008/xmemcached From 8976e6d97760174806f49b991c074a30f5c034bf Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Wed, 25 Oct 2017 19:40:53 +0800 Subject: [PATCH 120/207] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c800626ed..f0cc9cb26 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ 4.0.0 com.googlecode.xmemcached xmemcached - 2.4.0 + 2.4.1-SNAPSHOT xmemcached Extreme performance modern memcached client for java https://github.com/killme2008/xmemcached From 70f4c0d666a727b02bc54638f9131fac991f03a1 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Wed, 25 Oct 2017 20:20:15 +0800 Subject: [PATCH 121/207] (feat) adds news for 2.4.0 release --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 0931574e0..278494d43 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ ## News + +* [2.4.0](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.4.0) released, reduce CPU consumption when connecting to a lot of memcached servers. * [2.3.2](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.2) released, some fixes and add compatibility for `KetamaMemcachedSessionLocator` with Gwhalin Memcached Java Client. * [2.3.1](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.1) released, Adds `AWSElasticCacheClientBuilder` to build `AWSElasticCacheClient`. * [2.3.0](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.0) released, suppports [AWS ElasticCache Auto Discovery](http://docs.aws.amazon.com/AmazonElastiCache/latest/UserGuide/AutoDiscovery.html). From 0469f1b375c47a7335db4b1d0ded3e8fb3a912e4 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Thu, 23 Nov 2017 21:26:13 +0800 Subject: [PATCH 122/207] (feat) format code with google code style --- eclipse-java-google-style.xml | 337 ++ .../code/yanf4j/buffer/AbstractIoBuffer.java | 5166 ++++++++--------- .../yanf4j/buffer/BufferDataException.java | 30 +- .../yanf4j/buffer/CachedBufferAllocator.java | 481 +- .../google/code/yanf4j/buffer/IoBuffer.java | 2847 +++++---- .../code/yanf4j/buffer/IoBufferAllocator.java | 60 +- .../code/yanf4j/buffer/IoBufferHexDumper.java | 168 +- .../code/yanf4j/buffer/IoBufferWrapper.java | 1851 +++--- .../yanf4j/buffer/SimpleBufferAllocator.java | 174 +- .../code/yanf4j/config/Configuration.java | 10 +- .../google/code/yanf4j/core/Controller.java | 3 +- .../yanf4j/core/impl/AbstractController.java | 47 +- .../yanf4j/core/impl/AbstractSession.java | 12 +- .../code/yanf4j/core/impl/FutureImpl.java | 7 +- .../code/yanf4j/core/impl/FutureLockImpl.java | 332 +- .../code/yanf4j/core/impl/PoolDispatcher.java | 18 +- .../core/impl/TextLineCodecFactory.java | 32 +- .../google/code/yanf4j/nio/TCPController.java | 22 +- .../code/yanf4j/nio/impl/NioController.java | 20 +- .../code/yanf4j/nio/impl/NioTCPSession.java | 40 +- .../code/yanf4j/nio/impl/SelectorManager.java | 8 +- .../nio/impl/SocketChannelController.java | 49 +- .../statistics/impl/SimpleStatistics.java | 52 +- .../code/yanf4j/util/ByteBufferUtils.java | 13 +- .../code/yanf4j/util/CircularQueue.java | 27 +- .../code/yanf4j/util/ConcurrentHashSet.java | 3 +- .../code/yanf4j/util/DispatcherFactory.java | 6 +- .../code/yanf4j/util/LinkedTransferQueue.java | 1586 ++--- .../google/code/yanf4j/util/MapBackedSet.java | 88 +- .../code/yanf4j/util/ResourcesUtils.java | 4 +- .../code/yanf4j/util/SelectorFactory.java | 269 +- .../yanf4j/util/ShiftOrByteBufferMatcher.java | 130 +- .../google/code/yanf4j/util/SystemUtils.java | 13 +- .../code/yanf4j/util/TransferQueue.java | 206 +- .../code/yanf4j/util/WorkerThreadFactory.java | 15 +- .../rubyeye/xmemcached/CommandFactory.java | 22 +- .../java/net/rubyeye/xmemcached/Counter.java | 31 +- .../net/rubyeye/xmemcached/GetsResponse.java | 6 +- .../net/rubyeye/xmemcached/HashAlgorithm.java | 199 +- .../net/rubyeye/xmemcached/KeyIterator.java | 4 +- .../rubyeye/xmemcached/MemcachedClient.java | 1228 ++-- .../xmemcached/MemcachedClientBuilder.java | 7 +- .../xmemcached/MemcachedClientCallable.java | 4 +- .../MemcachedClientStateListener.java | 3 +- .../rubyeye/xmemcached/XMemcachedClient.java | 417 +- .../xmemcached/XMemcachedClientBuilder.java | 32 +- .../xmemcached/XMemcachedClientMBean.java | 9 +- .../net/rubyeye/xmemcached/auth/AuthInfo.java | 10 +- .../auth/AuthMemcachedConnectListener.java | 13 +- .../net/rubyeye/xmemcached/auth/AuthTask.java | 104 +- .../xmemcached/auth/PlainCallbackHandler.java | 12 +- .../xmemcached/aws/AWSElasticCacheClient.java | 28 +- .../net/rubyeye/xmemcached/aws/AWSUtils.java | 12 +- .../xmemcached/aws/ClusterConfigration.java | 4 +- .../xmemcached/aws/ConfigurationPoller.java | 9 +- .../buffer/CachedBufferAllocator.java | 47 +- .../rubyeye/xmemcached/buffer/IoBuffer.java | 6 +- .../buffer/SimpleBufferAllocator.java | 5 +- .../xmemcached/buffer/SimpleIoBuffer.java | 25 +- .../command/BinaryCommandFactory.java | 21 +- .../rubyeye/xmemcached/command/Command.java | 27 +- .../command/KestrelCommandFactory.java | 7 +- .../xmemcached/command/OperationStatus.java | 3 +- .../command/ServerAddressAware.java | 4 +- .../command/TextCommandFactory.java | 32 +- .../xmemcached/command/VerbosityCommand.java | 2 +- .../command/binary/BaseBinaryCommand.java | 143 +- .../BinaryAWSElasticCacheConfigCommand.java | 4 +- .../binary/BinaryAppendPrependCommand.java | 18 +- .../BinaryAuthListMechanismsCommand.java | 3 +- .../command/binary/BinaryAuthStepCommand.java | 4 +- .../command/binary/BinaryCASCommand.java | 19 +- .../command/binary/BinaryDecodeStatus.java | 3 +- .../command/binary/BinaryDeleteCommand.java | 5 +- .../command/binary/BinaryFlushAllCommand.java | 3 +- .../binary/BinaryGetAndTouchCommand.java | 21 +- .../command/binary/BinaryGetCommand.java | 12 +- .../command/binary/BinaryGetMultiCommand.java | 16 +- .../command/binary/BinaryIncrDecrCommand.java | 23 +- .../command/binary/BinarySetMultiCommand.java | 5 +- .../command/binary/BinaryStatsCommand.java | 9 +- .../command/binary/BinaryStoreCommand.java | 30 +- .../command/binary/BinaryVersionCommand.java | 6 +- .../command/binary/ResponseStatus.java | 78 +- .../command/kestrel/KestrelGetCommand.java | 1 + .../command/kestrel/KestrelSetCommand.java | 1 + .../TextAWSElasticCacheConfigCommand.java | 4 +- .../command/text/TextCASCommand.java | 15 +- .../command/text/TextCacheDumpCommand.java | 6 +- .../command/text/TextFlushAllCommand.java | 16 +- .../command/text/TextGetCommand.java | 293 +- .../command/text/TextGetMultiCommand.java | 3 +- .../command/text/TextIncrDecrCommand.java | 11 +- .../command/text/TextQuitCommand.java | 3 +- .../command/text/TextStatsCommand.java | 10 +- .../command/text/TextStoreCommand.java | 32 +- .../command/text/TextTouchCommand.java | 7 +- .../command/text/TextVerbosityCommand.java | 7 +- .../command/text/TextVersionCommand.java | 3 +- .../exception/MemcachedClientException.java | 1 + .../exception/MemcachedDecodeException.java | 1 + .../exception/MemcachedServerException.java | 1 + .../exception/NoValueException.java | 1 + .../impl/AbstractMemcachedSessionLocator.java | 5 +- .../impl/ArrayMemcachedSessionLocator.java | 11 +- .../impl/ClosedMemcachedTCPSession.java | 1 - .../xmemcached/impl/ConnectFuture.java | 1 - .../impl/ElectionMemcachedSessionLocator.java | 16 +- .../impl/FlowControlLinkedTransferQueue.java | 5 +- .../impl/KetamaMemcachedSessionLocator.java | 19 +- .../xmemcached/impl/KeyIteratorImpl.java | 21 +- .../LibmemcachedMemcachedSessionLocator.java | 7 +- .../MemcachedClientStateListenerAdapter.java | 10 +- .../xmemcached/impl/MemcachedConnector.java | 94 +- .../xmemcached/impl/MemcachedHandler.java | 66 +- .../impl/MemcachedSessionComparator.java | 6 +- .../xmemcached/impl/MemcachedTCPSession.java | 28 +- .../rubyeye/xmemcached/impl/Optimizer.java | 103 +- .../xmemcached/impl/OptimizerMBean.java | 2 - .../impl/PHPMemcacheSessionLocator.java | 10 +- .../xmemcached/impl/ReconnectRequest.java | 158 +- .../RoundRobinMemcachedSessionLocator.java | 5 +- .../rubyeye/xmemcached/monitor/Constants.java | 16 +- .../monitor/MemcachedClientNameHolder.java | 4 +- .../xmemcached/monitor/StatisticsHandler.java | 7 +- .../monitor/StatisticsHandlerMBean.java | 3 +- .../monitor/XMemcachedMbeanServer.java | 20 +- .../networking/ClosedMemcachedSession.java | 2 +- .../BaseSerializingTranscoder.java | 50 +- .../xmemcached/transcoders/CachedData.java | 12 +- .../transcoders/CompressionMode.java | 16 +- .../transcoders/IntegerTranscoder.java | 4 +- .../transcoders/LongTranscoder.java | 3 +- .../transcoders/PrimitiveTypeTranscoder.java | 7 +- .../transcoders/SerializingTranscoder.java | 81 +- .../transcoders/TokyoTyrantTranscoder.java | 8 +- .../xmemcached/transcoders/Transcoder.java | 6 +- .../transcoders/TranscoderUtils.java | 2 +- .../transcoders/WhalinTranscoder.java | 108 +- .../transcoders/WhalinV1Transcoder.java | 93 +- .../rubyeye/xmemcached/utils/AddrUtil.java | 54 +- .../rubyeye/xmemcached/utils/ByteUtils.java | 94 +- .../xmemcached/utils/CachedString.java | 7 +- .../utils/InetSocketAddressWrapper.java | 3 +- .../utils/XMemcachedClientFactoryBean.java | 4 +- .../code/yanf4j/test/unittest/Main.java | 8 +- .../code/yanf4j/test/unittest/buffer/Bar.java | 18 +- .../code/yanf4j/test/unittest/buffer/Foo.java | 19 +- .../test/unittest/buffer/IoBufferTest.java | 2331 ++++---- .../unittest/core/SocketOptionUnitTest.java | 26 +- .../core/impl/AbstractControllerUnitTest.java | 286 +- .../impl/ByteBufferCodecFactoryUnitTest.java | 109 +- .../core/impl/FutureImplUnitTest.java | 214 +- .../core/impl/FutureLockImplUnitTest.java | 209 +- .../core/impl/PoolDispatcherUnitTest.java | 9 +- .../impl/TextLineCodecFactoryUnitTest.java | 12 +- .../nio/impl/MockSelectableChannel.java | 136 +- .../unittest/nio/impl/MockSelectionKey.java | 90 +- .../unittest/nio/impl/ReactorUnitTest.java | 413 +- .../nio/impl/SelectorManagerUnitTest.java | 181 +- .../statistics/SimpleStatisticsTest.java | 2 +- .../unittest/utils/ByteBufferMatcherTest.java | 44 +- .../unittest/utils/ByteBufferUtilsTest.java | 38 +- .../utils/DispatcherFactoryUnitTest.java | 6 +- .../utils/ShiftAndByteBufferMatcherTest.java | 6 +- .../utils/ShiftOrByteBufferMatcherTest.java | 6 +- .../unittest/utils/SystemUtilsUniTest.java | 3 +- .../example/BinaryProtocolExample.java | 5 +- .../xmemcached/example/CASExample.java | 13 +- .../MemcachedStateListenerExample.java | 12 +- .../xmemcached/example/SASLExample.java | 11 +- .../xmemcached/example/SimpleExample.java | 7 +- .../xmemcached/example/SpringExample.java | 4 +- .../xmemcached/helper/AbstractChecker.java | 25 +- .../xmemcached/helper/InValidKeyChecker.java | 4 +- .../xmemcached/helper/MockTranscoder.java | 4 +- .../xmemcached/helper/TooLongKeyChecker.java | 9 +- .../xmemcached/helper/TranscoderChecker.java | 4 +- .../pressure/MemcachedClientPressureTest.java | 2 +- .../unittest/AWSElasticCacheClientIT.java | 4 +- .../unittest/BinaryMemcachedClientIT.java | 33 +- .../ConnectionPoolMemcachedClientIT.java | 15 +- .../ConsistentHashMemcachedClientIT.java | 13 +- .../test/unittest/FailureModeUnitTest.java | 54 +- .../test/unittest/KestrelClientIT.java | 55 +- .../test/unittest/MockMemcachedSession.java | 22 +- .../xmemcached/test/unittest/MockSession.java | 1 - .../StandardHashMemcachedClientIT.java | 13 +- .../test/unittest/XMemcachedClientIT.java | 171 +- .../XMemcachedClientWithKeyProviderIT.java | 9 +- .../AbstractBufferAllocatorUnitTest.java | 2 +- .../buffer/BufferAllocatorTestSuite.java | 4 +- .../buffer/CachedBufferAllocatorUnitTest.java | 5 +- .../buffer/SimpleBufferAllocatorUnitTest.java | 5 +- .../codec/MemcachedDecoderUnitTest.java | 9 +- .../codec/MemcachedEncoderUnitTest.java | 4 +- .../BinaryAppendPrependCommandUnitTest.java | 13 +- .../binary/BinaryCASCommandUnitTest.java | 17 +- .../binary/BinaryCommandAllTests.java | 4 +- .../binary/BinaryDeleteCommandUnitTest.java | 3 +- .../BinaryGetAndTouchCommandUnitTest.java | 12 +- .../binary/BinaryGetCommandUnitTest.java | 8 +- .../binary/BinaryGetMultiCommandUnitTest.java | 61 +- .../binary/BinaryIncrDecrUnitTest.java | 62 +- .../binary/BinaryStatsCommandUnitTest.java | 16 +- .../binary/BinaryStoreCommandUnitTest.java | 28 +- .../factory/TextCommandFactoryTest.java | 29 +- .../text/BaseTextCommandUnitTest.java | 18 +- .../commands/text/TextCommandsAllTests.java | 4 +- .../text/TextFlushAllCommandUnitTest.java | 44 +- .../text/TextGetMultiCommandUnitTest.java | 53 +- .../text/TextGetOneCommandUnitTest.java | 60 +- .../text/TextStatsCommandUnitTest.java | 6 +- .../text/TextStoreCommandUnitTest.java | 70 +- .../text/TextVerbositylCommandUnitTest.java | 24 +- .../text/TextVersionCommandUnitTest.java | 12 +- .../ArrayMemcachedSessionLocatorUnitTest.java | 9 +- ...torGwhalinMemcachedJavaClientUnitTest.java | 13 +- ...ocatorNginxUpstreamConsistentUnitTest.java | 13 +- ...KetamaMemcachedSessionLocatorUnitTest.java | 5 +- .../impl/MemcachedClientStateListenerIT.java | 10 +- .../impl/MemcachedHandlerUnitTest.java | 4 +- .../MemcachedSessionComparatorUnitTest.java | 2 +- .../MockMemcachedClientStateListener.java | 13 +- .../test/unittest/impl/OptimizerTest.java | 47 +- ...dRobinMemcachedSessionLocatorUnitTest.java | 5 +- .../unittest/impl/SessionLocatorTest.java | 4 +- .../MockDecodeTimeoutBinaryGetOneCommand.java | 4 +- .../MockEncodeTimeoutBinaryGetCommand.java | 2 +- .../mock/MockErrorBinaryGetOneCommand.java | 11 +- .../mock/MockErrorTextGetOneCommand.java | 4 +- .../test/unittest/monitor/Mock.java | 1 - .../XMemcachedMBeanServerUnitTest.java | 6 +- .../BaseSerializingTranscoderTest.java | 16 +- .../transcoder/BaseTranscoderCase.java | 69 +- .../unittest/transcoder/CachedDataTest.java | 12 +- .../transcoder/IntegerTranscoderTest.java | 10 +- .../transcoder/LongTranscoderTest.java | 10 +- .../transcoder/PrimitiveAsStringUnitTest.java | 110 +- .../transcoder/SerializingTranscoderTest.java | 4 +- .../TokyoTyrantTranscoderUnitTest.java | 27 +- .../transcoder/TranscoderUtilsTest.java | 22 +- .../transcoder/WhalinTranscoderTest.java | 53 +- .../transcoder/WhalinV1TranscoderTest.java | 3 +- .../test/unittest/utils/AddrUtilTest.java | 13 +- .../utils/OpaqueGeneraterUnitTest.java | 5 +- 246 files changed, 11969 insertions(+), 12216 deletions(-) create mode 100644 eclipse-java-google-style.xml diff --git a/eclipse-java-google-style.xml b/eclipse-java-google-style.xml new file mode 100644 index 000000000..7bb6804eb --- /dev/null +++ b/eclipse-java-google-style.xml @@ -0,0 +1,337 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/com/google/code/yanf4j/buffer/AbstractIoBuffer.java b/src/main/java/com/google/code/yanf4j/buffer/AbstractIoBuffer.java index 27f1d6217..3ec79c739 100644 --- a/src/main/java/com/google/code/yanf4j/buffer/AbstractIoBuffer.java +++ b/src/main/java/com/google/code/yanf4j/buffer/AbstractIoBuffer.java @@ -44,7 +44,6 @@ import java.util.EnumSet; import java.util.Set; - /** * A base implementation of {@link IoBuffer}. This implementation assumes that * {@link IoBuffer#buf()} always returns a correct NIO {@link ByteBuffer} @@ -57,2655 +56,2518 @@ * @see IoBufferAllocator */ public abstract class AbstractIoBuffer extends IoBuffer { - /** Tells if a buffer has been created from an existing buffer */ - private final boolean derived; - - /** A flag set to true if the buffer can extend automatically */ - private boolean autoExpand; - - /** A flag set to true if the buffer can shrink automatically */ - private boolean autoShrink; - - /** Tells if a buffer can be expanded */ - private boolean recapacityAllowed = true; - - /** The minimum number of bytes the IoBuffer can hold */ - private int minimumCapacity; - - /** A mask for a byte */ - private static final long BYTE_MASK = 0xFFL; - - /** A mask for a short */ - private static final long SHORT_MASK = 0xFFFFL; - - /** A mask for an int */ - private static final long INT_MASK = 0xFFFFFFFFL; - - /** - * We don't have any access to Buffer.markValue(), so we need to track it - * down, which will cause small extra overhead. - */ - private int mark = -1; - - - /** - * Creates a new parent buffer. - * - * @param allocator - * The allocator to use to create new buffers - * @param initialCapacity - * The initial buffer capacity when created - */ - protected AbstractIoBuffer(IoBufferAllocator allocator, int initialCapacity) { - setAllocator(allocator); - this.recapacityAllowed = true; - this.derived = false; - this.minimumCapacity = initialCapacity; - } - - - /** - * Creates a new derived buffer. A derived buffer uses an existing buffer - * properties - the allocator and capacity -. - * - * @param parent - * The buffer we get the properties from - */ - protected AbstractIoBuffer(AbstractIoBuffer parent) { - setAllocator(parent.getAllocator()); - this.recapacityAllowed = false; - this.derived = true; - this.minimumCapacity = parent.minimumCapacity; - } - - - /** - * {@inheritDoc} - */ - @Override - public final boolean isDirect() { - return buf().isDirect(); - } - - - /** - * {@inheritDoc} - */ - @Override - public final boolean isReadOnly() { - return buf().isReadOnly(); - } - - - /** - * Sets the underlying NIO buffer instance. - * - * @param newBuf - * The buffer to store within this IoBuffer - */ - protected abstract void buf(ByteBuffer newBuf); - - - /** - * {@inheritDoc} - */ - @Override - public final int minimumCapacity() { - return minimumCapacity; - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer minimumCapacity(int minimumCapacity) { - if (minimumCapacity < 0) { - throw new IllegalArgumentException("minimumCapacity: " + minimumCapacity); - } - this.minimumCapacity = minimumCapacity; - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final int capacity() { - return buf().capacity(); - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer capacity(int newCapacity) { - if (!recapacityAllowed) { - throw new IllegalStateException("Derived buffers and their parent can't be expanded."); - } - - // Allocate a new buffer and transfer all settings to it. - if (newCapacity > capacity()) { - // Expand: - // // Save the state. - int pos = position(); - int limit = limit(); - ByteOrder bo = order(); - - // // Reallocate. - ByteBuffer oldBuf = buf(); - ByteBuffer newBuf = getAllocator().allocateNioBuffer(newCapacity, isDirect()); - oldBuf.clear(); - newBuf.put(oldBuf); - buf(newBuf); - - // // Restore the state. - buf().limit(limit); - if (mark >= 0) { - buf().position(mark); - buf().mark(); - } - buf().position(pos); - buf().order(bo); - } - - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final boolean isAutoExpand() { - return autoExpand && recapacityAllowed; - } - - - /** - * {@inheritDoc} - */ - @Override - public final boolean isAutoShrink() { - return autoShrink && recapacityAllowed; - } - - - /** - * {@inheritDoc} - */ - @Override - public final boolean isDerived() { - return derived; - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer setAutoExpand(boolean autoExpand) { - if (!recapacityAllowed) { - throw new IllegalStateException("Derived buffers and their parent can't be expanded."); - } - this.autoExpand = autoExpand; - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer setAutoShrink(boolean autoShrink) { - if (!recapacityAllowed) { - throw new IllegalStateException("Derived buffers and their parent can't be shrinked."); - } - this.autoShrink = autoShrink; - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer expand(int expectedRemaining) { - return expand(position(), expectedRemaining, false); - } - - - private IoBuffer expand(int expectedRemaining, boolean autoExpand) { - return expand(position(), expectedRemaining, autoExpand); - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer expand(int pos, int expectedRemaining) { - return expand(pos, expectedRemaining, false); - } - - - private IoBuffer expand(int pos, int expectedRemaining, boolean autoExpand) { - if (!recapacityAllowed) { - throw new IllegalStateException("Derived buffers and their parent can't be expanded."); - } - - int end = pos + expectedRemaining; - int newCapacity; - if (autoExpand) { - newCapacity = IoBuffer.normalizeCapacity(end); - } - else { - newCapacity = end; - } - if (newCapacity > capacity()) { - // The buffer needs expansion. - capacity(newCapacity); - } - - if (end > limit()) { - // We call limit() directly to prevent StackOverflowError - buf().limit(end); - } - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer shrink() { - - if (!recapacityAllowed) { - throw new IllegalStateException("Derived buffers and their parent can't be expanded."); - } - - int position = position(); - int capacity = capacity(); - int limit = limit(); - if (capacity == limit) { - return this; - } - - int newCapacity = capacity; - int minCapacity = Math.max(minimumCapacity, limit); - for (;;) { - if (newCapacity >>> 1 < minCapacity) { - break; - } - newCapacity >>>= 1; - } - - newCapacity = Math.max(minCapacity, newCapacity); - - if (newCapacity == capacity) { - return this; - } - - // Shrink and compact: - // // Save the state. - ByteOrder bo = order(); - - // // Reallocate. - ByteBuffer oldBuf = buf(); - ByteBuffer newBuf = getAllocator().allocateNioBuffer(newCapacity, isDirect()); - oldBuf.position(0); - oldBuf.limit(limit); - newBuf.put(oldBuf); - buf(newBuf); - - // // Restore the state. - buf().position(position); - buf().limit(limit); - buf().order(bo); - mark = -1; - - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final int position() { - return buf().position(); - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer position(int newPosition) { - autoExpand(newPosition, 0); - buf().position(newPosition); - if (mark > newPosition) { - mark = -1; - } - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final int limit() { - return buf().limit(); - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer limit(int newLimit) { - autoExpand(newLimit, 0); - buf().limit(newLimit); - if (mark > newLimit) { - mark = -1; - } - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer mark() { - buf().mark(); - mark = position(); - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final int markValue() { - return mark; - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer reset() { - buf().reset(); - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer clear() { - buf().clear(); - mark = -1; - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer sweep() { - clear(); - return fillAndReset(remaining()); - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer sweep(byte value) { - clear(); - return fillAndReset(value, remaining()); - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer flip() { - buf().flip(); - mark = -1; - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer rewind() { - buf().rewind(); - mark = -1; - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final int remaining() { - return limit() - position(); - } - - - /** - * {@inheritDoc} - */ - @Override - public final boolean hasRemaining() { - return limit() > position(); - } - - - /** - * {@inheritDoc} - */ - @Override - public final byte get() { - return buf().get(); - } - - - /** - * {@inheritDoc} - */ - @Override - public final short getUnsigned() { - return (short) (get() & 0xff); - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer put(byte b) { - autoExpand(1); - buf().put(b); - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final byte get(int index) { - return buf().get(index); - } - - - /** - * {@inheritDoc} - */ - @Override - public final short getUnsigned(int index) { - return (short) (get(index) & 0xff); - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer put(int index, byte b) { - autoExpand(index, 1); - buf().put(index, b); - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer get(byte[] dst, int offset, int length) { - buf().get(dst, offset, length); - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer put(ByteBuffer src) { - autoExpand(src.remaining()); - buf().put(src); - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer put(byte[] src, int offset, int length) { - autoExpand(length); - buf().put(src, offset, length); - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer compact() { - int remaining = remaining(); - int capacity = capacity(); - - if (capacity == 0) { - return this; - } - - if (isAutoShrink() && remaining <= capacity >>> 2 && capacity > minimumCapacity) { - int newCapacity = capacity; - int minCapacity = Math.max(minimumCapacity, remaining << 1); - for (;;) { - if (newCapacity >>> 1 < minCapacity) { - break; - } - newCapacity >>>= 1; - } - - newCapacity = Math.max(minCapacity, newCapacity); - - if (newCapacity == capacity) { - return this; - } - - // Shrink and compact: - // // Save the state. - ByteOrder bo = order(); - - // // Sanity check. - if (remaining > newCapacity) { - throw new IllegalStateException("The amount of the remaining bytes is greater than " - + "the new capacity."); - } - - // // Reallocate. - ByteBuffer oldBuf = buf(); - ByteBuffer newBuf = getAllocator().allocateNioBuffer(newCapacity, isDirect()); - newBuf.put(oldBuf); - buf(newBuf); - - // // Restore the state. - buf().order(bo); - } - else { - buf().compact(); - } - mark = -1; - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final ByteOrder order() { - return buf().order(); - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer order(ByteOrder bo) { - buf().order(bo); - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final char getChar() { - return buf().getChar(); - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer putChar(char value) { - autoExpand(2); - buf().putChar(value); - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final char getChar(int index) { - return buf().getChar(index); - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer putChar(int index, char value) { - autoExpand(index, 2); - buf().putChar(index, value); - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final CharBuffer asCharBuffer() { - return buf().asCharBuffer(); - } - - - /** - * {@inheritDoc} - */ - @Override - public final short getShort() { - return buf().getShort(); - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer putShort(short value) { - autoExpand(2); - buf().putShort(value); - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final short getShort(int index) { - return buf().getShort(index); - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer putShort(int index, short value) { - autoExpand(index, 2); - buf().putShort(index, value); - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final ShortBuffer asShortBuffer() { - return buf().asShortBuffer(); - } - - - /** - * {@inheritDoc} - */ - @Override - public final int getInt() { - return buf().getInt(); - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer putInt(int value) { - autoExpand(4); - buf().putInt(value); - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final int getInt(int index) { - return buf().getInt(index); - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer putInt(int index, int value) { - autoExpand(index, 4); - buf().putInt(index, value); - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final IntBuffer asIntBuffer() { - return buf().asIntBuffer(); - } - - - /** - * {@inheritDoc} - */ - @Override - public final long getLong() { - return buf().getLong(); - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer putLong(long value) { - autoExpand(8); - buf().putLong(value); - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final long getLong(int index) { - return buf().getLong(index); - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer putLong(int index, long value) { - autoExpand(index, 8); - buf().putLong(index, value); - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final LongBuffer asLongBuffer() { - return buf().asLongBuffer(); - } - - - /** - * {@inheritDoc} - */ - @Override - public final float getFloat() { - return buf().getFloat(); - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer putFloat(float value) { - autoExpand(4); - buf().putFloat(value); - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final float getFloat(int index) { - return buf().getFloat(index); - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer putFloat(int index, float value) { - autoExpand(index, 4); - buf().putFloat(index, value); - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final FloatBuffer asFloatBuffer() { - return buf().asFloatBuffer(); - } - - - /** - * {@inheritDoc} - */ - @Override - public final double getDouble() { - return buf().getDouble(); - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer putDouble(double value) { - autoExpand(8); - buf().putDouble(value); - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final double getDouble(int index) { - return buf().getDouble(index); - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer putDouble(int index, double value) { - autoExpand(index, 8); - buf().putDouble(index, value); - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public final DoubleBuffer asDoubleBuffer() { - return buf().asDoubleBuffer(); - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer asReadOnlyBuffer() { - recapacityAllowed = false; - return asReadOnlyBuffer0(); - } - - - /** - * Implement this method to return the unexpandable read only version of - * this buffer. - */ - protected abstract IoBuffer asReadOnlyBuffer0(); - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer duplicate() { - recapacityAllowed = false; - return duplicate0(); - } - - - /** - * Implement this method to return the unexpandable duplicate of this - * buffer. - */ - protected abstract IoBuffer duplicate0(); - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer slice() { - recapacityAllowed = false; - return slice0(); - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer getSlice(int index, int length) { - if (length < 0) { - throw new IllegalArgumentException("length: " + length); - } - - int limit = limit(); - - if (index > limit) { - throw new IllegalArgumentException("index: " + index); - } - - int endIndex = index + length; - - if (capacity() < endIndex) { - throw new IndexOutOfBoundsException("index + length (" + endIndex + ") is greater " + "than capacity (" - + capacity() + ")."); - } - - clear(); - position(index); - limit(endIndex); - - IoBuffer slice = slice(); - position(index); - limit(limit); - return slice; - } - - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer getSlice(int length) { - if (length < 0) { - throw new IllegalArgumentException("length: " + length); - } - int pos = position(); - int limit = limit(); - int nextPos = pos + length; - if (limit < nextPos) { - throw new IndexOutOfBoundsException("position + length (" + nextPos + ") is greater " + "than limit (" - + limit + ")."); - } - - limit(pos + length); - IoBuffer slice = slice(); - position(nextPos); - limit(limit); - return slice; - } - - - /** - * Implement this method to return the unexpandable slice of this buffer. - */ - protected abstract IoBuffer slice0(); - - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - int h = 1; - int p = position(); - for (int i = limit() - 1; i >= p; i--) { - h = 31 * h + get(i); - } - return h; - } - - - /** - * {@inheritDoc} - */ - @Override - public boolean equals(Object o) { - if (!(o instanceof IoBuffer)) { - return false; - } - - IoBuffer that = (IoBuffer) o; - if (this.remaining() != that.remaining()) { - return false; - } - - int p = this.position(); - for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--) { - byte v1 = this.get(i); - byte v2 = that.get(j); - if (v1 != v2) { - return false; - } - } - return true; - } - - - /** - * {@inheritDoc} - */ - public int compareTo(IoBuffer that) { - int n = this.position() + Math.min(this.remaining(), that.remaining()); - for (int i = this.position(), j = that.position(); i < n; i++, j++) { - byte v1 = this.get(i); - byte v2 = that.get(j); - if (v1 == v2) { - continue; - } - if (v1 < v2) { - return -1; - } - - return +1; - } - return this.remaining() - that.remaining(); - } - - - /** - * {@inheritDoc} - */ - @Override - public String toString() { - StringBuilder buf = new StringBuilder(); - if (isDirect()) { - buf.append("DirectBuffer"); - } - else { - buf.append("HeapBuffer"); - } - buf.append("[pos="); - buf.append(position()); - buf.append(" lim="); - buf.append(limit()); - buf.append(" cap="); - buf.append(capacity()); - buf.append(": "); - buf.append(getHexDump(16)); - buf.append(']'); - return buf.toString(); - } - - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer get(byte[] dst) { - return get(dst, 0, dst.length); - } - - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer put(IoBuffer src) { - return put(src.buf()); - } - - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer put(byte[] src) { - return put(src, 0, src.length); - } - - - /** - * {@inheritDoc} - */ - @Override - public int getUnsignedShort() { - return getShort() & 0xffff; - } - - - /** - * {@inheritDoc} - */ - @Override - public int getUnsignedShort(int index) { - return getShort(index) & 0xffff; - } - - - /** - * {@inheritDoc} - */ - @Override - public long getUnsignedInt() { - return getInt() & 0xffffffffL; - } - - - /** - * {@inheritDoc} - */ - @Override - public int getMediumInt() { - byte b1 = get(); - byte b2 = get(); - byte b3 = get(); - if (ByteOrder.BIG_ENDIAN.equals(order())) { - return getMediumInt(b1, b2, b3); - } - else { - return getMediumInt(b3, b2, b1); - } - } - - - /** - * {@inheritDoc} - */ - @Override - public int getUnsignedMediumInt() { - int b1 = getUnsigned(); - int b2 = getUnsigned(); - int b3 = getUnsigned(); - if (ByteOrder.BIG_ENDIAN.equals(order())) { - return b1 << 16 | b2 << 8 | b3; - } - else { - return b3 << 16 | b2 << 8 | b1; - } - } - - - /** - * {@inheritDoc} - */ - @Override - public int getMediumInt(int index) { - byte b1 = get(index); - byte b2 = get(index + 1); - byte b3 = get(index + 2); - if (ByteOrder.BIG_ENDIAN.equals(order())) { - return getMediumInt(b1, b2, b3); - } - else { - return getMediumInt(b3, b2, b1); - } - } - - - /** - * {@inheritDoc} - */ - @Override - public int getUnsignedMediumInt(int index) { - int b1 = getUnsigned(index); - int b2 = getUnsigned(index + 1); - int b3 = getUnsigned(index + 2); - if (ByteOrder.BIG_ENDIAN.equals(order())) { - return b1 << 16 | b2 << 8 | b3; - } - else { - return b3 << 16 | b2 << 8 | b1; - } - } - - - /** - * {@inheritDoc} - */ - private int getMediumInt(byte b1, byte b2, byte b3) { - int ret = b1 << 16 & 0xff0000 | b2 << 8 & 0xff00 | b3 & 0xff; - // Check to see if the medium int is negative (high bit in b1 set) - if ((b1 & 0x80) == 0x80) { - // Make the the whole int negative - ret |= 0xff000000; - } - return ret; - } - - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putMediumInt(int value) { - byte b1 = (byte) (value >> 16); - byte b2 = (byte) (value >> 8); - byte b3 = (byte) value; - - if (ByteOrder.BIG_ENDIAN.equals(order())) { - put(b1).put(b2).put(b3); - } - else { - put(b3).put(b2).put(b1); - } - - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putMediumInt(int index, int value) { - byte b1 = (byte) (value >> 16); - byte b2 = (byte) (value >> 8); - byte b3 = (byte) value; - - if (ByteOrder.BIG_ENDIAN.equals(order())) { - put(index, b1).put(index + 1, b2).put(index + 2, b3); - } - else { - put(index, b3).put(index + 1, b2).put(index + 2, b1); - } - - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public long getUnsignedInt(int index) { - return getInt(index) & 0xffffffffL; - } - - - /** - * {@inheritDoc} - */ - @Override - public InputStream asInputStream() { - return new InputStream() { - @Override - public int available() { - return AbstractIoBuffer.this.remaining(); - } - - - @Override - public synchronized void mark(int readlimit) { - AbstractIoBuffer.this.mark(); - } - - - @Override - public boolean markSupported() { - return true; - } - - - @Override - public int read() { - if (AbstractIoBuffer.this.hasRemaining()) { - return AbstractIoBuffer.this.get() & 0xff; - } - else { - return -1; - } - } - - - @Override - public int read(byte[] b, int off, int len) { - int remaining = AbstractIoBuffer.this.remaining(); - if (remaining > 0) { - int readBytes = Math.min(remaining, len); - AbstractIoBuffer.this.get(b, off, readBytes); - return readBytes; - } - else { - return -1; - } - } - - - @Override - public synchronized void reset() { - AbstractIoBuffer.this.reset(); - } - - - @Override - public long skip(long n) { - int bytes; - if (n > Integer.MAX_VALUE) { - bytes = AbstractIoBuffer.this.remaining(); - } - else { - bytes = Math.min(AbstractIoBuffer.this.remaining(), (int) n); - } - AbstractIoBuffer.this.skip(bytes); - return bytes; - } - }; - } - - - /** - * {@inheritDoc} - */ - @Override - public OutputStream asOutputStream() { - return new OutputStream() { - @Override - public void write(byte[] b, int off, int len) { - AbstractIoBuffer.this.put(b, off, len); - } - - - @Override - public void write(int b) { - AbstractIoBuffer.this.put((byte) b); - } - }; - } - - - /** - * {@inheritDoc} - */ - @Override - public String getHexDump() { - return this.getHexDump(Integer.MAX_VALUE); - } - - - /** - * {@inheritDoc} - */ - @Override - public String getHexDump(int lengthLimit) { - return IoBufferHexDumper.getHexdump(this, lengthLimit); - } - - - /** - * {@inheritDoc} - */ - @Override - public String getString(CharsetDecoder decoder) throws CharacterCodingException { - if (!hasRemaining()) { - return ""; - } - - boolean utf16 = decoder.charset().name().startsWith("UTF-16"); - - int oldPos = position(); - int oldLimit = limit(); - int end = -1; - int newPos; - - if (!utf16) { - end = indexOf((byte) 0x00); - if (end < 0) { - newPos = end = oldLimit; - } - else { - newPos = end + 1; - } - } - else { - int i = oldPos; - for (;;) { - boolean wasZero = get(i) == 0; - i++; - - if (i >= oldLimit) { - break; - } - - if (get(i) != 0) { - i++; - if (i >= oldLimit) { - break; - } - else { - continue; - } - } - - if (wasZero) { - end = i - 1; - break; - } - } - - if (end < 0) { - newPos = end = oldPos + (oldLimit - oldPos & 0xFFFFFFFE); - } - else { - if (end + 2 <= oldLimit) { - newPos = end + 2; - } - else { - newPos = end; - } - } - } - - if (oldPos == end) { - position(newPos); - return ""; - } - - limit(end); - decoder.reset(); - - int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1; - CharBuffer out = CharBuffer.allocate(expectedLength); - for (;;) { - CoderResult cr; - if (hasRemaining()) { - cr = decoder.decode(buf(), out, true); - } - else { - cr = decoder.flush(out); - } - - if (cr.isUnderflow()) { - break; - } - - if (cr.isOverflow()) { - CharBuffer o = CharBuffer.allocate(out.capacity() + expectedLength); - out.flip(); - o.put(out); - out = o; - continue; - } - - if (cr.isError()) { - // Revert the buffer back to the previous state. - limit(oldLimit); - position(oldPos); - cr.throwException(); - } - } - - limit(oldLimit); - position(newPos); - return out.flip().toString(); - } - - - /** - * {@inheritDoc} - */ - @Override - public String getString(int fieldSize, CharsetDecoder decoder) throws CharacterCodingException { - checkFieldSize(fieldSize); - - if (fieldSize == 0) { - return ""; - } - - if (!hasRemaining()) { - return ""; - } - - boolean utf16 = decoder.charset().name().startsWith("UTF-16"); - - if (utf16 && (fieldSize & 1) != 0) { - throw new IllegalArgumentException("fieldSize is not even."); - } - - int oldPos = position(); - int oldLimit = limit(); - int end = oldPos + fieldSize; - - if (oldLimit < end) { - throw new BufferUnderflowException(); - } - - int i; - - if (!utf16) { - for (i = oldPos; i < end; i++) { - if (get(i) == 0) { - break; - } - } - - if (i == end) { - limit(end); - } - else { - limit(i); - } - } - else { - for (i = oldPos; i < end; i += 2) { - if (get(i) == 0 && get(i + 1) == 0) { - break; - } - } - - if (i == end) { - limit(end); - } - else { - limit(i); - } - } - - if (!hasRemaining()) { - limit(oldLimit); - position(end); - return ""; - } - decoder.reset(); - - int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1; - CharBuffer out = CharBuffer.allocate(expectedLength); - for (;;) { - CoderResult cr; - if (hasRemaining()) { - cr = decoder.decode(buf(), out, true); - } - else { - cr = decoder.flush(out); - } - - if (cr.isUnderflow()) { - break; - } - - if (cr.isOverflow()) { - CharBuffer o = CharBuffer.allocate(out.capacity() + expectedLength); - out.flip(); - o.put(out); - out = o; - continue; - } - - if (cr.isError()) { - // Revert the buffer back to the previous state. - limit(oldLimit); - position(oldPos); - cr.throwException(); - } - } - - limit(oldLimit); - position(end); - return out.flip().toString(); - } - - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putString(CharSequence val, CharsetEncoder encoder) throws CharacterCodingException { - if (val.length() == 0) { - return this; - } - - CharBuffer in = CharBuffer.wrap(val); - encoder.reset(); - - int expandedState = 0; - - for (;;) { - CoderResult cr; - if (in.hasRemaining()) { - cr = encoder.encode(in, buf(), true); - } - else { - cr = encoder.flush(buf()); - } - - if (cr.isUnderflow()) { - break; - } - if (cr.isOverflow()) { - if (isAutoExpand()) { - switch (expandedState) { - case 0: - autoExpand((int) Math.ceil(in.remaining() * encoder.averageBytesPerChar())); - expandedState++; - break; - case 1: - autoExpand((int) Math.ceil(in.remaining() * encoder.maxBytesPerChar())); - expandedState++; - break; - default: - throw new RuntimeException("Expanded by " - + (int) Math.ceil(in.remaining() * encoder.maxBytesPerChar()) - + " but that wasn't enough for '" + val + "'"); - } - continue; - } - } - else { - expandedState = 0; - } - cr.throwException(); - } - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putString(CharSequence val, int fieldSize, CharsetEncoder encoder) throws CharacterCodingException { - checkFieldSize(fieldSize); - - if (fieldSize == 0) { - return this; - } - - autoExpand(fieldSize); - - boolean utf16 = encoder.charset().name().startsWith("UTF-16"); - - if (utf16 && (fieldSize & 1) != 0) { - throw new IllegalArgumentException("fieldSize is not even."); - } - - int oldLimit = limit(); - int end = position() + fieldSize; - - if (oldLimit < end) { - throw new BufferOverflowException(); - } - - if (val.length() == 0) { - if (!utf16) { - put((byte) 0x00); - } - else { - put((byte) 0x00); - put((byte) 0x00); - } - position(end); - return this; - } - - CharBuffer in = CharBuffer.wrap(val); - limit(end); - encoder.reset(); - - for (;;) { - CoderResult cr; - if (in.hasRemaining()) { - cr = encoder.encode(in, buf(), true); - } - else { - cr = encoder.flush(buf()); - } - - if (cr.isUnderflow() || cr.isOverflow()) { - break; - } - cr.throwException(); - } - - limit(oldLimit); - - if (position() < end) { - if (!utf16) { - put((byte) 0x00); - } - else { - put((byte) 0x00); - put((byte) 0x00); - } - } - - position(end); - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public String getPrefixedString(CharsetDecoder decoder) throws CharacterCodingException { - return getPrefixedString(2, decoder); - } - - - /** - * Reads a string which has a length field before the actual encoded string, - * using the specified decoder and returns it. - * - * @param prefixLength - * the length of the length field (1, 2, or 4) - * @param decoder - * the decoder to use for decoding the string - * @return the prefixed string - * @throws CharacterCodingException - * when decoding fails - * @throws BufferUnderflowException - * when there is not enough data available - */ - @Override - public String getPrefixedString(int prefixLength, CharsetDecoder decoder) throws CharacterCodingException { - if (!prefixedDataAvailable(prefixLength)) { - throw new BufferUnderflowException(); - } - - int fieldSize = 0; - - switch (prefixLength) { - case 1: - fieldSize = getUnsigned(); - break; - case 2: - fieldSize = getUnsignedShort(); - break; - case 4: - fieldSize = getInt(); - break; - } - - if (fieldSize == 0) { - return ""; - } - - boolean utf16 = decoder.charset().name().startsWith("UTF-16"); - - if (utf16 && (fieldSize & 1) != 0) { - throw new BufferDataException("fieldSize is not even for a UTF-16 string."); - } - - int oldLimit = limit(); - int end = position() + fieldSize; - - if (oldLimit < end) { - throw new BufferUnderflowException(); - } - - limit(end); - decoder.reset(); - - int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1; - CharBuffer out = CharBuffer.allocate(expectedLength); - for (;;) { - CoderResult cr; - if (hasRemaining()) { - cr = decoder.decode(buf(), out, true); - } - else { - cr = decoder.flush(out); - } - - if (cr.isUnderflow()) { - break; - } - - if (cr.isOverflow()) { - CharBuffer o = CharBuffer.allocate(out.capacity() + expectedLength); - out.flip(); - o.put(out); - out = o; - continue; - } - - cr.throwException(); - } - - limit(oldLimit); - position(end); - return out.flip().toString(); - } - - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putPrefixedString(CharSequence in, CharsetEncoder encoder) throws CharacterCodingException { - return putPrefixedString(in, 2, 0, encoder); - } - - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putPrefixedString(CharSequence in, int prefixLength, CharsetEncoder encoder) - throws CharacterCodingException { - return putPrefixedString(in, prefixLength, 0, encoder); - } - - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putPrefixedString(CharSequence in, int prefixLength, int padding, CharsetEncoder encoder) - throws CharacterCodingException { - return putPrefixedString(in, prefixLength, padding, (byte) 0, encoder); - } - - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putPrefixedString(CharSequence val, int prefixLength, int padding, byte padValue, - CharsetEncoder encoder) throws CharacterCodingException { - int maxLength; - switch (prefixLength) { - case 1: - maxLength = 255; - break; - case 2: - maxLength = 65535; - break; - case 4: - maxLength = Integer.MAX_VALUE; - break; - default: - throw new IllegalArgumentException("prefixLength: " + prefixLength); - } - - if (val.length() > maxLength) { - throw new IllegalArgumentException("The specified string is too long."); - } - if (val.length() == 0) { - switch (prefixLength) { - case 1: - put((byte) 0); - break; - case 2: - putShort((short) 0); - break; - case 4: - putInt(0); - break; - } - return this; - } - - int padMask; - switch (padding) { - case 0: - case 1: - padMask = 0; - break; - case 2: - padMask = 1; - break; - case 4: - padMask = 3; - break; - default: - throw new IllegalArgumentException("padding: " + padding); - } - - CharBuffer in = CharBuffer.wrap(val); - skip(prefixLength); // make a room for the length field - int oldPos = position(); - encoder.reset(); - - int expandedState = 0; - - for (;;) { - CoderResult cr; - if (in.hasRemaining()) { - cr = encoder.encode(in, buf(), true); - } - else { - cr = encoder.flush(buf()); - } - - if (position() - oldPos > maxLength) { - throw new IllegalArgumentException("The specified string is too long."); - } - - if (cr.isUnderflow()) { - break; - } - if (cr.isOverflow()) { - if (isAutoExpand()) { - switch (expandedState) { - case 0: - autoExpand((int) Math.ceil(in.remaining() * encoder.averageBytesPerChar())); - expandedState++; - break; - case 1: - autoExpand((int) Math.ceil(in.remaining() * encoder.maxBytesPerChar())); - expandedState++; - break; - default: - throw new RuntimeException("Expanded by " - + (int) Math.ceil(in.remaining() * encoder.maxBytesPerChar()) - + " but that wasn't enough for '" + val + "'"); - } - continue; - } - } - else { - expandedState = 0; - } - cr.throwException(); - } - - // Write the length field - fill(padValue, padding - (position() - oldPos & padMask)); - int length = position() - oldPos; - switch (prefixLength) { - case 1: - put(oldPos - 1, (byte) length); - break; - case 2: - putShort(oldPos - 2, (short) length); - break; - case 4: - putInt(oldPos - 4, length); - break; - } - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public Object getObject() throws ClassNotFoundException { - return getObject(Thread.currentThread().getContextClassLoader()); - } - - - /** - * {@inheritDoc} - */ - @Override - public Object getObject(final ClassLoader classLoader) throws ClassNotFoundException { - if (!prefixedDataAvailable(4)) { - throw new BufferUnderflowException(); - } - - int length = getInt(); - if (length <= 4) { - throw new BufferDataException("Object length should be greater than 4: " + length); - } - - int oldLimit = limit(); - limit(position() + length); - try { - ObjectInputStream in = new ObjectInputStream(asInputStream()) { - @Override - protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException { - int type = read(); - if (type < 0) { - throw new EOFException(); - } - switch (type) { - case 0: // Primitive types - return super.readClassDescriptor(); - case 1: // Non-primitive types - String className = readUTF(); - Class clazz = Class.forName(className, true, classLoader); - return ObjectStreamClass.lookup(clazz); - default: - throw new StreamCorruptedException("Unexpected class descriptor type: " + type); - } - } - - - @Override - protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { - String name = desc.getName(); - try { - return Class.forName(name, false, classLoader); - } - catch (ClassNotFoundException ex) { - return super.resolveClass(desc); - } - } - }; - return in.readObject(); - } - catch (IOException e) { - throw new BufferDataException(e); - } - finally { - limit(oldLimit); - } - } - - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putObject(Object o) { - int oldPos = position(); - skip(4); // Make a room for the length field. - try { - ObjectOutputStream out = new ObjectOutputStream(asOutputStream()) { - @Override - protected void writeClassDescriptor(ObjectStreamClass desc) throws IOException { - if (desc.forClass().isPrimitive()) { - write(0); - super.writeClassDescriptor(desc); - } - else { - write(1); - writeUTF(desc.getName()); - } - } - }; - out.writeObject(o); - out.flush(); - } - catch (IOException e) { - throw new BufferDataException(e); - } - - // Fill the length field - int newPos = position(); - position(oldPos); - putInt(newPos - oldPos - 4); - position(newPos); - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public boolean prefixedDataAvailable(int prefixLength) { - return prefixedDataAvailable(prefixLength, Integer.MAX_VALUE); - } - - - /** - * {@inheritDoc} - */ - @Override - public boolean prefixedDataAvailable(int prefixLength, int maxDataLength) { - if (remaining() < prefixLength) { - return false; - } - - int dataLength; - switch (prefixLength) { - case 1: - dataLength = getUnsigned(position()); - break; - case 2: - dataLength = getUnsignedShort(position()); - break; - case 4: - dataLength = getInt(position()); - break; - default: - throw new IllegalArgumentException("prefixLength: " + prefixLength); - } - - if (dataLength < 0 || dataLength > maxDataLength) { - throw new BufferDataException("dataLength: " + dataLength); - } - - return remaining() - prefixLength >= dataLength; - } - - - /** - * {@inheritDoc} - */ - @Override - public int indexOf(byte b) { - if (hasArray()) { - int arrayOffset = arrayOffset(); - int beginPos = arrayOffset + position(); - int limit = arrayOffset + limit(); - byte[] array = array(); - - for (int i = beginPos; i < limit; i++) { - if (array[i] == b) { - return i - arrayOffset; - } - } - } - else { - int beginPos = position(); - int limit = limit(); - - for (int i = beginPos; i < limit; i++) { - if (get(i) == b) { - return i; - } - } - } - - return -1; - } - - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer skip(int size) { - autoExpand(size); - return position(position() + size); - } - - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer fill(byte value, int size) { - autoExpand(size); - int q = size >>> 3; - int r = size & 7; - - if (q > 0) { - int intValue = value | value << 8 | value << 16 | value << 24; - long longValue = intValue; - longValue <<= 32; - longValue |= intValue; - - for (int i = q; i > 0; i--) { - putLong(longValue); - } - } - - q = r >>> 2; - r = r & 3; - - if (q > 0) { - int intValue = value | value << 8 | value << 16 | value << 24; - putInt(intValue); - } - - q = r >> 1; - r = r & 1; - - if (q > 0) { - short shortValue = (short) (value | value << 8); - putShort(shortValue); - } - - if (r > 0) { - put(value); - } - - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer fillAndReset(byte value, int size) { - autoExpand(size); - int pos = position(); - try { - fill(value, size); - } - finally { - position(pos); - } - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer fill(int size) { - autoExpand(size); - int q = size >>> 3; - int r = size & 7; - - for (int i = q; i > 0; i--) { - putLong(0L); - } - - q = r >>> 2; - r = r & 3; - - if (q > 0) { - putInt(0); - } - - q = r >> 1; - r = r & 1; - - if (q > 0) { - putShort((short) 0); - } - - if (r > 0) { - put((byte) 0); - } - - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer fillAndReset(int size) { - autoExpand(size); - int pos = position(); - try { - fill(size); - } - finally { - position(pos); - } - - return this; - } - - - /** - * {@inheritDoc} - */ - @Override - public > E getEnum(Class enumClass) { - return toEnum(enumClass, getUnsigned()); - } - - - /** - * {@inheritDoc} - */ - @Override - public > E getEnum(int index, Class enumClass) { - return toEnum(enumClass, getUnsigned(index)); - } - - - /** - * {@inheritDoc} - */ - @Override - public > E getEnumShort(Class enumClass) { - return toEnum(enumClass, getUnsignedShort()); - } - - - /** - * {@inheritDoc} - */ - @Override - public > E getEnumShort(int index, Class enumClass) { - return toEnum(enumClass, getUnsignedShort(index)); - } - - - /** - * {@inheritDoc} - */ - @Override - public > E getEnumInt(Class enumClass) { - return toEnum(enumClass, getInt()); - } - - - /** - * {@inheritDoc} - */ - @Override - public > E getEnumInt(int index, Class enumClass) { - return toEnum(enumClass, getInt(index)); - } - - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putEnum(Enum e) { - if (e.ordinal() > BYTE_MASK) { - throw new IllegalArgumentException(enumConversionErrorMessage(e, "byte")); - } - return put((byte) e.ordinal()); - } - - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putEnum(int index, Enum e) { - if (e.ordinal() > BYTE_MASK) { - throw new IllegalArgumentException(enumConversionErrorMessage(e, "byte")); - } - return put(index, (byte) e.ordinal()); - } - - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putEnumShort(Enum e) { - if (e.ordinal() > SHORT_MASK) { - throw new IllegalArgumentException(enumConversionErrorMessage(e, "short")); - } - return putShort((short) e.ordinal()); - } - - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putEnumShort(int index, Enum e) { - if (e.ordinal() > SHORT_MASK) { - throw new IllegalArgumentException(enumConversionErrorMessage(e, "short")); - } - return putShort(index, (short) e.ordinal()); - } - - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putEnumInt(Enum e) { - return putInt(e.ordinal()); - } - - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putEnumInt(int index, Enum e) { - return putInt(index, e.ordinal()); - } - - - private E toEnum(Class enumClass, int i) { - E[] enumConstants = enumClass.getEnumConstants(); - if (i > enumConstants.length) { - throw new IndexOutOfBoundsException(String.format( - "%d is too large of an ordinal to convert to the enum %s", i, enumClass.getName())); - } - return enumConstants[i]; - } - - - private String enumConversionErrorMessage(Enum e, String type) { - return String.format("%s.%s has an ordinal value too large for a %s", e.getClass().getName(), e.name(), type); - } - - - /** - * {@inheritDoc} - */ - @Override - public > EnumSet getEnumSet(Class enumClass) { - return toEnumSet(enumClass, get() & BYTE_MASK); - } - - - /** - * {@inheritDoc} - */ - @Override - public > EnumSet getEnumSet(int index, Class enumClass) { - return toEnumSet(enumClass, get(index) & BYTE_MASK); - } - - - /** - * {@inheritDoc} - */ - @Override - public > EnumSet getEnumSetShort(Class enumClass) { - return toEnumSet(enumClass, getShort() & SHORT_MASK); - } - - - /** - * {@inheritDoc} - */ - @Override - public > EnumSet getEnumSetShort(int index, Class enumClass) { - return toEnumSet(enumClass, getShort(index) & SHORT_MASK); - } - - - /** - * {@inheritDoc} - */ - @Override - public > EnumSet getEnumSetInt(Class enumClass) { - return toEnumSet(enumClass, getInt() & INT_MASK); - } - - - /** - * {@inheritDoc} - */ - @Override - public > EnumSet getEnumSetInt(int index, Class enumClass) { - return toEnumSet(enumClass, getInt(index) & INT_MASK); - } - - - /** - * {@inheritDoc} - */ - @Override - public > EnumSet getEnumSetLong(Class enumClass) { - return toEnumSet(enumClass, getLong()); - } - - - /** - * {@inheritDoc} - */ - @Override - public > EnumSet getEnumSetLong(int index, Class enumClass) { - return toEnumSet(enumClass, getLong(index)); - } - - - private > EnumSet toEnumSet(Class clazz, long vector) { - EnumSet set = EnumSet.noneOf(clazz); - long mask = 1; - for (E e : clazz.getEnumConstants()) { - if ((mask & vector) == mask) { - set.add(e); - } - mask <<= 1; - } - return set; - } - - - /** - * {@inheritDoc} - */ - @Override - public > IoBuffer putEnumSet(Set set) { - long vector = toLong(set); - if ((vector & ~BYTE_MASK) != 0) { - throw new IllegalArgumentException("The enum set is too large to fit in a byte: " + set); - } - return put((byte) vector); - } - - - /** - * {@inheritDoc} - */ - @Override - public > IoBuffer putEnumSet(int index, Set set) { - long vector = toLong(set); - if ((vector & ~BYTE_MASK) != 0) { - throw new IllegalArgumentException("The enum set is too large to fit in a byte: " + set); - } - return put(index, (byte) vector); - } - - - /** - * {@inheritDoc} - */ - @Override - public > IoBuffer putEnumSetShort(Set set) { - long vector = toLong(set); - if ((vector & ~SHORT_MASK) != 0) { - throw new IllegalArgumentException("The enum set is too large to fit in a short: " + set); - } - return putShort((short) vector); - } - - - /** - * {@inheritDoc} - */ - @Override - public > IoBuffer putEnumSetShort(int index, Set set) { - long vector = toLong(set); - if ((vector & ~SHORT_MASK) != 0) { - throw new IllegalArgumentException("The enum set is too large to fit in a short: " + set); - } - return putShort(index, (short) vector); - } - - - /** - * {@inheritDoc} - */ - @Override - public > IoBuffer putEnumSetInt(Set set) { - long vector = toLong(set); - if ((vector & ~INT_MASK) != 0) { - throw new IllegalArgumentException("The enum set is too large to fit in an int: " + set); - } - return putInt((int) vector); - } - - - /** - * {@inheritDoc} - */ - @Override - public > IoBuffer putEnumSetInt(int index, Set set) { - long vector = toLong(set); - if ((vector & ~INT_MASK) != 0) { - throw new IllegalArgumentException("The enum set is too large to fit in an int: " + set); - } - return putInt(index, (int) vector); - } - - - /** - * {@inheritDoc} - */ - @Override - public > IoBuffer putEnumSetLong(Set set) { - return putLong(toLong(set)); - } - - - /** - * {@inheritDoc} - */ - @Override - public > IoBuffer putEnumSetLong(int index, Set set) { - return putLong(index, toLong(set)); - } - - - private > long toLong(Set set) { - long vector = 0; - for (E e : set) { - if (e.ordinal() >= Long.SIZE) { - throw new IllegalArgumentException("The enum set is too large to fit in a bit vector: " + set); - } - vector |= 1L << e.ordinal(); - } - return vector; - } - - - /** - * This method forwards the call to {@link #expand(int)} only when - * autoExpand property is true. - */ - private IoBuffer autoExpand(int expectedRemaining) { - if (isAutoExpand()) { - expand(expectedRemaining, true); - } - return this; - } - - - /** - * This method forwards the call to {@link #expand(int)} only when - * autoExpand property is true. - */ - private IoBuffer autoExpand(int pos, int expectedRemaining) { - if (isAutoExpand()) { - expand(pos, expectedRemaining, true); - } - return this; - } - - - private static void checkFieldSize(int fieldSize) { - if (fieldSize < 0) { - throw new IllegalArgumentException("fieldSize cannot be negative: " + fieldSize); - } - } + /** Tells if a buffer has been created from an existing buffer */ + private final boolean derived; + + /** A flag set to true if the buffer can extend automatically */ + private boolean autoExpand; + + /** A flag set to true if the buffer can shrink automatically */ + private boolean autoShrink; + + /** Tells if a buffer can be expanded */ + private boolean recapacityAllowed = true; + + /** The minimum number of bytes the IoBuffer can hold */ + private int minimumCapacity; + + /** A mask for a byte */ + private static final long BYTE_MASK = 0xFFL; + + /** A mask for a short */ + private static final long SHORT_MASK = 0xFFFFL; + + /** A mask for an int */ + private static final long INT_MASK = 0xFFFFFFFFL; + + /** + * We don't have any access to Buffer.markValue(), so we need to track it + * down, which will cause small extra overhead. + */ + private int mark = -1; + + /** + * Creates a new parent buffer. + * + * @param allocator + * The allocator to use to create new buffers + * @param initialCapacity + * The initial buffer capacity when created + */ + protected AbstractIoBuffer(IoBufferAllocator allocator, + int initialCapacity) { + setAllocator(allocator); + this.recapacityAllowed = true; + this.derived = false; + this.minimumCapacity = initialCapacity; + } + + /** + * Creates a new derived buffer. A derived buffer uses an existing buffer + * properties - the allocator and capacity -. + * + * @param parent + * The buffer we get the properties from + */ + protected AbstractIoBuffer(AbstractIoBuffer parent) { + setAllocator(parent.getAllocator()); + this.recapacityAllowed = false; + this.derived = true; + this.minimumCapacity = parent.minimumCapacity; + } + + /** + * {@inheritDoc} + */ + @Override + public final boolean isDirect() { + return buf().isDirect(); + } + + /** + * {@inheritDoc} + */ + @Override + public final boolean isReadOnly() { + return buf().isReadOnly(); + } + + /** + * Sets the underlying NIO buffer instance. + * + * @param newBuf + * The buffer to store within this IoBuffer + */ + protected abstract void buf(ByteBuffer newBuf); + + /** + * {@inheritDoc} + */ + @Override + public final int minimumCapacity() { + return minimumCapacity; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer minimumCapacity(int minimumCapacity) { + if (minimumCapacity < 0) { + throw new IllegalArgumentException( + "minimumCapacity: " + minimumCapacity); + } + this.minimumCapacity = minimumCapacity; + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final int capacity() { + return buf().capacity(); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer capacity(int newCapacity) { + if (!recapacityAllowed) { + throw new IllegalStateException( + "Derived buffers and their parent can't be expanded."); + } + + // Allocate a new buffer and transfer all settings to it. + if (newCapacity > capacity()) { + // Expand: + // // Save the state. + int pos = position(); + int limit = limit(); + ByteOrder bo = order(); + + // // Reallocate. + ByteBuffer oldBuf = buf(); + ByteBuffer newBuf = getAllocator().allocateNioBuffer(newCapacity, + isDirect()); + oldBuf.clear(); + newBuf.put(oldBuf); + buf(newBuf); + + // // Restore the state. + buf().limit(limit); + if (mark >= 0) { + buf().position(mark); + buf().mark(); + } + buf().position(pos); + buf().order(bo); + } + + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final boolean isAutoExpand() { + return autoExpand && recapacityAllowed; + } + + /** + * {@inheritDoc} + */ + @Override + public final boolean isAutoShrink() { + return autoShrink && recapacityAllowed; + } + + /** + * {@inheritDoc} + */ + @Override + public final boolean isDerived() { + return derived; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer setAutoExpand(boolean autoExpand) { + if (!recapacityAllowed) { + throw new IllegalStateException( + "Derived buffers and their parent can't be expanded."); + } + this.autoExpand = autoExpand; + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer setAutoShrink(boolean autoShrink) { + if (!recapacityAllowed) { + throw new IllegalStateException( + "Derived buffers and their parent can't be shrinked."); + } + this.autoShrink = autoShrink; + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer expand(int expectedRemaining) { + return expand(position(), expectedRemaining, false); + } + + private IoBuffer expand(int expectedRemaining, boolean autoExpand) { + return expand(position(), expectedRemaining, autoExpand); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer expand(int pos, int expectedRemaining) { + return expand(pos, expectedRemaining, false); + } + + private IoBuffer expand(int pos, int expectedRemaining, + boolean autoExpand) { + if (!recapacityAllowed) { + throw new IllegalStateException( + "Derived buffers and their parent can't be expanded."); + } + + int end = pos + expectedRemaining; + int newCapacity; + if (autoExpand) { + newCapacity = IoBuffer.normalizeCapacity(end); + } else { + newCapacity = end; + } + if (newCapacity > capacity()) { + // The buffer needs expansion. + capacity(newCapacity); + } + + if (end > limit()) { + // We call limit() directly to prevent StackOverflowError + buf().limit(end); + } + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer shrink() { + + if (!recapacityAllowed) { + throw new IllegalStateException( + "Derived buffers and their parent can't be expanded."); + } + + int position = position(); + int capacity = capacity(); + int limit = limit(); + if (capacity == limit) { + return this; + } + + int newCapacity = capacity; + int minCapacity = Math.max(minimumCapacity, limit); + for (;;) { + if (newCapacity >>> 1 < minCapacity) { + break; + } + newCapacity >>>= 1; + } + + newCapacity = Math.max(minCapacity, newCapacity); + + if (newCapacity == capacity) { + return this; + } + + // Shrink and compact: + // // Save the state. + ByteOrder bo = order(); + + // // Reallocate. + ByteBuffer oldBuf = buf(); + ByteBuffer newBuf = getAllocator().allocateNioBuffer(newCapacity, + isDirect()); + oldBuf.position(0); + oldBuf.limit(limit); + newBuf.put(oldBuf); + buf(newBuf); + + // // Restore the state. + buf().position(position); + buf().limit(limit); + buf().order(bo); + mark = -1; + + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final int position() { + return buf().position(); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer position(int newPosition) { + autoExpand(newPosition, 0); + buf().position(newPosition); + if (mark > newPosition) { + mark = -1; + } + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final int limit() { + return buf().limit(); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer limit(int newLimit) { + autoExpand(newLimit, 0); + buf().limit(newLimit); + if (mark > newLimit) { + mark = -1; + } + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer mark() { + buf().mark(); + mark = position(); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final int markValue() { + return mark; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer reset() { + buf().reset(); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer clear() { + buf().clear(); + mark = -1; + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer sweep() { + clear(); + return fillAndReset(remaining()); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer sweep(byte value) { + clear(); + return fillAndReset(value, remaining()); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer flip() { + buf().flip(); + mark = -1; + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer rewind() { + buf().rewind(); + mark = -1; + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final int remaining() { + return limit() - position(); + } + + /** + * {@inheritDoc} + */ + @Override + public final boolean hasRemaining() { + return limit() > position(); + } + + /** + * {@inheritDoc} + */ + @Override + public final byte get() { + return buf().get(); + } + + /** + * {@inheritDoc} + */ + @Override + public final short getUnsigned() { + return (short) (get() & 0xff); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer put(byte b) { + autoExpand(1); + buf().put(b); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final byte get(int index) { + return buf().get(index); + } + + /** + * {@inheritDoc} + */ + @Override + public final short getUnsigned(int index) { + return (short) (get(index) & 0xff); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer put(int index, byte b) { + autoExpand(index, 1); + buf().put(index, b); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer get(byte[] dst, int offset, int length) { + buf().get(dst, offset, length); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer put(ByteBuffer src) { + autoExpand(src.remaining()); + buf().put(src); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer put(byte[] src, int offset, int length) { + autoExpand(length); + buf().put(src, offset, length); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer compact() { + int remaining = remaining(); + int capacity = capacity(); + + if (capacity == 0) { + return this; + } + + if (isAutoShrink() && remaining <= capacity >>> 2 + && capacity > minimumCapacity) { + int newCapacity = capacity; + int minCapacity = Math.max(minimumCapacity, remaining << 1); + for (;;) { + if (newCapacity >>> 1 < minCapacity) { + break; + } + newCapacity >>>= 1; + } + + newCapacity = Math.max(minCapacity, newCapacity); + + if (newCapacity == capacity) { + return this; + } + + // Shrink and compact: + // // Save the state. + ByteOrder bo = order(); + + // // Sanity check. + if (remaining > newCapacity) { + throw new IllegalStateException( + "The amount of the remaining bytes is greater than " + + "the new capacity."); + } + + // // Reallocate. + ByteBuffer oldBuf = buf(); + ByteBuffer newBuf = getAllocator().allocateNioBuffer(newCapacity, + isDirect()); + newBuf.put(oldBuf); + buf(newBuf); + + // // Restore the state. + buf().order(bo); + } else { + buf().compact(); + } + mark = -1; + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final ByteOrder order() { + return buf().order(); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer order(ByteOrder bo) { + buf().order(bo); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final char getChar() { + return buf().getChar(); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer putChar(char value) { + autoExpand(2); + buf().putChar(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final char getChar(int index) { + return buf().getChar(index); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer putChar(int index, char value) { + autoExpand(index, 2); + buf().putChar(index, value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final CharBuffer asCharBuffer() { + return buf().asCharBuffer(); + } + + /** + * {@inheritDoc} + */ + @Override + public final short getShort() { + return buf().getShort(); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer putShort(short value) { + autoExpand(2); + buf().putShort(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final short getShort(int index) { + return buf().getShort(index); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer putShort(int index, short value) { + autoExpand(index, 2); + buf().putShort(index, value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final ShortBuffer asShortBuffer() { + return buf().asShortBuffer(); + } + + /** + * {@inheritDoc} + */ + @Override + public final int getInt() { + return buf().getInt(); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer putInt(int value) { + autoExpand(4); + buf().putInt(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final int getInt(int index) { + return buf().getInt(index); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer putInt(int index, int value) { + autoExpand(index, 4); + buf().putInt(index, value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final IntBuffer asIntBuffer() { + return buf().asIntBuffer(); + } + + /** + * {@inheritDoc} + */ + @Override + public final long getLong() { + return buf().getLong(); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer putLong(long value) { + autoExpand(8); + buf().putLong(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final long getLong(int index) { + return buf().getLong(index); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer putLong(int index, long value) { + autoExpand(index, 8); + buf().putLong(index, value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final LongBuffer asLongBuffer() { + return buf().asLongBuffer(); + } + + /** + * {@inheritDoc} + */ + @Override + public final float getFloat() { + return buf().getFloat(); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer putFloat(float value) { + autoExpand(4); + buf().putFloat(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final float getFloat(int index) { + return buf().getFloat(index); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer putFloat(int index, float value) { + autoExpand(index, 4); + buf().putFloat(index, value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final FloatBuffer asFloatBuffer() { + return buf().asFloatBuffer(); + } + + /** + * {@inheritDoc} + */ + @Override + public final double getDouble() { + return buf().getDouble(); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer putDouble(double value) { + autoExpand(8); + buf().putDouble(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final double getDouble(int index) { + return buf().getDouble(index); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer putDouble(int index, double value) { + autoExpand(index, 8); + buf().putDouble(index, value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final DoubleBuffer asDoubleBuffer() { + return buf().asDoubleBuffer(); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer asReadOnlyBuffer() { + recapacityAllowed = false; + return asReadOnlyBuffer0(); + } + + /** + * Implement this method to return the unexpandable read only version of + * this buffer. + */ + protected abstract IoBuffer asReadOnlyBuffer0(); + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer duplicate() { + recapacityAllowed = false; + return duplicate0(); + } + + /** + * Implement this method to return the unexpandable duplicate of this + * buffer. + */ + protected abstract IoBuffer duplicate0(); + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer slice() { + recapacityAllowed = false; + return slice0(); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer getSlice(int index, int length) { + if (length < 0) { + throw new IllegalArgumentException("length: " + length); + } + + int limit = limit(); + + if (index > limit) { + throw new IllegalArgumentException("index: " + index); + } + + int endIndex = index + length; + + if (capacity() < endIndex) { + throw new IndexOutOfBoundsException("index + length (" + endIndex + + ") is greater " + "than capacity (" + capacity() + ")."); + } + + clear(); + position(index); + limit(endIndex); + + IoBuffer slice = slice(); + position(index); + limit(limit); + return slice; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer getSlice(int length) { + if (length < 0) { + throw new IllegalArgumentException("length: " + length); + } + int pos = position(); + int limit = limit(); + int nextPos = pos + length; + if (limit < nextPos) { + throw new IndexOutOfBoundsException("position + length (" + nextPos + + ") is greater " + "than limit (" + limit + ")."); + } + + limit(pos + length); + IoBuffer slice = slice(); + position(nextPos); + limit(limit); + return slice; + } + + /** + * Implement this method to return the unexpandable slice of this buffer. + */ + protected abstract IoBuffer slice0(); + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + int h = 1; + int p = position(); + for (int i = limit() - 1; i >= p; i--) { + h = 31 * h + get(i); + } + return h; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof IoBuffer)) { + return false; + } + + IoBuffer that = (IoBuffer) o; + if (this.remaining() != that.remaining()) { + return false; + } + + int p = this.position(); + for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--) { + byte v1 = this.get(i); + byte v2 = that.get(j); + if (v1 != v2) { + return false; + } + } + return true; + } + + /** + * {@inheritDoc} + */ + public int compareTo(IoBuffer that) { + int n = this.position() + Math.min(this.remaining(), that.remaining()); + for (int i = this.position(), j = that.position(); i < n; i++, j++) { + byte v1 = this.get(i); + byte v2 = that.get(j); + if (v1 == v2) { + continue; + } + if (v1 < v2) { + return -1; + } + + return +1; + } + return this.remaining() - that.remaining(); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + if (isDirect()) { + buf.append("DirectBuffer"); + } else { + buf.append("HeapBuffer"); + } + buf.append("[pos="); + buf.append(position()); + buf.append(" lim="); + buf.append(limit()); + buf.append(" cap="); + buf.append(capacity()); + buf.append(": "); + buf.append(getHexDump(16)); + buf.append(']'); + return buf.toString(); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer get(byte[] dst) { + return get(dst, 0, dst.length); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer put(IoBuffer src) { + return put(src.buf()); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer put(byte[] src) { + return put(src, 0, src.length); + } + + /** + * {@inheritDoc} + */ + @Override + public int getUnsignedShort() { + return getShort() & 0xffff; + } + + /** + * {@inheritDoc} + */ + @Override + public int getUnsignedShort(int index) { + return getShort(index) & 0xffff; + } + + /** + * {@inheritDoc} + */ + @Override + public long getUnsignedInt() { + return getInt() & 0xffffffffL; + } + + /** + * {@inheritDoc} + */ + @Override + public int getMediumInt() { + byte b1 = get(); + byte b2 = get(); + byte b3 = get(); + if (ByteOrder.BIG_ENDIAN.equals(order())) { + return getMediumInt(b1, b2, b3); + } else { + return getMediumInt(b3, b2, b1); + } + } + + /** + * {@inheritDoc} + */ + @Override + public int getUnsignedMediumInt() { + int b1 = getUnsigned(); + int b2 = getUnsigned(); + int b3 = getUnsigned(); + if (ByteOrder.BIG_ENDIAN.equals(order())) { + return b1 << 16 | b2 << 8 | b3; + } else { + return b3 << 16 | b2 << 8 | b1; + } + } + + /** + * {@inheritDoc} + */ + @Override + public int getMediumInt(int index) { + byte b1 = get(index); + byte b2 = get(index + 1); + byte b3 = get(index + 2); + if (ByteOrder.BIG_ENDIAN.equals(order())) { + return getMediumInt(b1, b2, b3); + } else { + return getMediumInt(b3, b2, b1); + } + } + + /** + * {@inheritDoc} + */ + @Override + public int getUnsignedMediumInt(int index) { + int b1 = getUnsigned(index); + int b2 = getUnsigned(index + 1); + int b3 = getUnsigned(index + 2); + if (ByteOrder.BIG_ENDIAN.equals(order())) { + return b1 << 16 | b2 << 8 | b3; + } else { + return b3 << 16 | b2 << 8 | b1; + } + } + + /** + * {@inheritDoc} + */ + private int getMediumInt(byte b1, byte b2, byte b3) { + int ret = b1 << 16 & 0xff0000 | b2 << 8 & 0xff00 | b3 & 0xff; + // Check to see if the medium int is negative (high bit in b1 set) + if ((b1 & 0x80) == 0x80) { + // Make the the whole int negative + ret |= 0xff000000; + } + return ret; + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putMediumInt(int value) { + byte b1 = (byte) (value >> 16); + byte b2 = (byte) (value >> 8); + byte b3 = (byte) value; + + if (ByteOrder.BIG_ENDIAN.equals(order())) { + put(b1).put(b2).put(b3); + } else { + put(b3).put(b2).put(b1); + } + + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putMediumInt(int index, int value) { + byte b1 = (byte) (value >> 16); + byte b2 = (byte) (value >> 8); + byte b3 = (byte) value; + + if (ByteOrder.BIG_ENDIAN.equals(order())) { + put(index, b1).put(index + 1, b2).put(index + 2, b3); + } else { + put(index, b3).put(index + 1, b2).put(index + 2, b1); + } + + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public long getUnsignedInt(int index) { + return getInt(index) & 0xffffffffL; + } + + /** + * {@inheritDoc} + */ + @Override + public InputStream asInputStream() { + return new InputStream() { + @Override + public int available() { + return AbstractIoBuffer.this.remaining(); + } + + @Override + public synchronized void mark(int readlimit) { + AbstractIoBuffer.this.mark(); + } + + @Override + public boolean markSupported() { + return true; + } + + @Override + public int read() { + if (AbstractIoBuffer.this.hasRemaining()) { + return AbstractIoBuffer.this.get() & 0xff; + } else { + return -1; + } + } + + @Override + public int read(byte[] b, int off, int len) { + int remaining = AbstractIoBuffer.this.remaining(); + if (remaining > 0) { + int readBytes = Math.min(remaining, len); + AbstractIoBuffer.this.get(b, off, readBytes); + return readBytes; + } else { + return -1; + } + } + + @Override + public synchronized void reset() { + AbstractIoBuffer.this.reset(); + } + + @Override + public long skip(long n) { + int bytes; + if (n > Integer.MAX_VALUE) { + bytes = AbstractIoBuffer.this.remaining(); + } else { + bytes = Math.min(AbstractIoBuffer.this.remaining(), + (int) n); + } + AbstractIoBuffer.this.skip(bytes); + return bytes; + } + }; + } + + /** + * {@inheritDoc} + */ + @Override + public OutputStream asOutputStream() { + return new OutputStream() { + @Override + public void write(byte[] b, int off, int len) { + AbstractIoBuffer.this.put(b, off, len); + } + + @Override + public void write(int b) { + AbstractIoBuffer.this.put((byte) b); + } + }; + } + + /** + * {@inheritDoc} + */ + @Override + public String getHexDump() { + return this.getHexDump(Integer.MAX_VALUE); + } + + /** + * {@inheritDoc} + */ + @Override + public String getHexDump(int lengthLimit) { + return IoBufferHexDumper.getHexdump(this, lengthLimit); + } + + /** + * {@inheritDoc} + */ + @Override + public String getString(CharsetDecoder decoder) + throws CharacterCodingException { + if (!hasRemaining()) { + return ""; + } + + boolean utf16 = decoder.charset().name().startsWith("UTF-16"); + + int oldPos = position(); + int oldLimit = limit(); + int end = -1; + int newPos; + + if (!utf16) { + end = indexOf((byte) 0x00); + if (end < 0) { + newPos = end = oldLimit; + } else { + newPos = end + 1; + } + } else { + int i = oldPos; + for (;;) { + boolean wasZero = get(i) == 0; + i++; + + if (i >= oldLimit) { + break; + } + + if (get(i) != 0) { + i++; + if (i >= oldLimit) { + break; + } else { + continue; + } + } + + if (wasZero) { + end = i - 1; + break; + } + } + + if (end < 0) { + newPos = end = oldPos + (oldLimit - oldPos & 0xFFFFFFFE); + } else { + if (end + 2 <= oldLimit) { + newPos = end + 2; + } else { + newPos = end; + } + } + } + + if (oldPos == end) { + position(newPos); + return ""; + } + + limit(end); + decoder.reset(); + + int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + + 1; + CharBuffer out = CharBuffer.allocate(expectedLength); + for (;;) { + CoderResult cr; + if (hasRemaining()) { + cr = decoder.decode(buf(), out, true); + } else { + cr = decoder.flush(out); + } + + if (cr.isUnderflow()) { + break; + } + + if (cr.isOverflow()) { + CharBuffer o = CharBuffer + .allocate(out.capacity() + expectedLength); + out.flip(); + o.put(out); + out = o; + continue; + } + + if (cr.isError()) { + // Revert the buffer back to the previous state. + limit(oldLimit); + position(oldPos); + cr.throwException(); + } + } + + limit(oldLimit); + position(newPos); + return out.flip().toString(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getString(int fieldSize, CharsetDecoder decoder) + throws CharacterCodingException { + checkFieldSize(fieldSize); + + if (fieldSize == 0) { + return ""; + } + + if (!hasRemaining()) { + return ""; + } + + boolean utf16 = decoder.charset().name().startsWith("UTF-16"); + + if (utf16 && (fieldSize & 1) != 0) { + throw new IllegalArgumentException("fieldSize is not even."); + } + + int oldPos = position(); + int oldLimit = limit(); + int end = oldPos + fieldSize; + + if (oldLimit < end) { + throw new BufferUnderflowException(); + } + + int i; + + if (!utf16) { + for (i = oldPos; i < end; i++) { + if (get(i) == 0) { + break; + } + } + + if (i == end) { + limit(end); + } else { + limit(i); + } + } else { + for (i = oldPos; i < end; i += 2) { + if (get(i) == 0 && get(i + 1) == 0) { + break; + } + } + + if (i == end) { + limit(end); + } else { + limit(i); + } + } + + if (!hasRemaining()) { + limit(oldLimit); + position(end); + return ""; + } + decoder.reset(); + + int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + + 1; + CharBuffer out = CharBuffer.allocate(expectedLength); + for (;;) { + CoderResult cr; + if (hasRemaining()) { + cr = decoder.decode(buf(), out, true); + } else { + cr = decoder.flush(out); + } + + if (cr.isUnderflow()) { + break; + } + + if (cr.isOverflow()) { + CharBuffer o = CharBuffer + .allocate(out.capacity() + expectedLength); + out.flip(); + o.put(out); + out = o; + continue; + } + + if (cr.isError()) { + // Revert the buffer back to the previous state. + limit(oldLimit); + position(oldPos); + cr.throwException(); + } + } + + limit(oldLimit); + position(end); + return out.flip().toString(); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putString(CharSequence val, CharsetEncoder encoder) + throws CharacterCodingException { + if (val.length() == 0) { + return this; + } + + CharBuffer in = CharBuffer.wrap(val); + encoder.reset(); + + int expandedState = 0; + + for (;;) { + CoderResult cr; + if (in.hasRemaining()) { + cr = encoder.encode(in, buf(), true); + } else { + cr = encoder.flush(buf()); + } + + if (cr.isUnderflow()) { + break; + } + if (cr.isOverflow()) { + if (isAutoExpand()) { + switch (expandedState) { + case 0 : + autoExpand((int) Math.ceil(in.remaining() + * encoder.averageBytesPerChar())); + expandedState++; + break; + case 1 : + autoExpand((int) Math.ceil(in.remaining() + * encoder.maxBytesPerChar())); + expandedState++; + break; + default : + throw new RuntimeException("Expanded by " + + (int) Math.ceil(in.remaining() + * encoder.maxBytesPerChar()) + + " but that wasn't enough for '" + val + + "'"); + } + continue; + } + } else { + expandedState = 0; + } + cr.throwException(); + } + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putString(CharSequence val, int fieldSize, + CharsetEncoder encoder) throws CharacterCodingException { + checkFieldSize(fieldSize); + + if (fieldSize == 0) { + return this; + } + + autoExpand(fieldSize); + + boolean utf16 = encoder.charset().name().startsWith("UTF-16"); + + if (utf16 && (fieldSize & 1) != 0) { + throw new IllegalArgumentException("fieldSize is not even."); + } + + int oldLimit = limit(); + int end = position() + fieldSize; + + if (oldLimit < end) { + throw new BufferOverflowException(); + } + + if (val.length() == 0) { + if (!utf16) { + put((byte) 0x00); + } else { + put((byte) 0x00); + put((byte) 0x00); + } + position(end); + return this; + } + + CharBuffer in = CharBuffer.wrap(val); + limit(end); + encoder.reset(); + + for (;;) { + CoderResult cr; + if (in.hasRemaining()) { + cr = encoder.encode(in, buf(), true); + } else { + cr = encoder.flush(buf()); + } + + if (cr.isUnderflow() || cr.isOverflow()) { + break; + } + cr.throwException(); + } + + limit(oldLimit); + + if (position() < end) { + if (!utf16) { + put((byte) 0x00); + } else { + put((byte) 0x00); + put((byte) 0x00); + } + } + + position(end); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public String getPrefixedString(CharsetDecoder decoder) + throws CharacterCodingException { + return getPrefixedString(2, decoder); + } + + /** + * Reads a string which has a length field before the actual encoded string, + * using the specified decoder and returns it. + * + * @param prefixLength + * the length of the length field (1, 2, or 4) + * @param decoder + * the decoder to use for decoding the string + * @return the prefixed string + * @throws CharacterCodingException + * when decoding fails + * @throws BufferUnderflowException + * when there is not enough data available + */ + @Override + public String getPrefixedString(int prefixLength, CharsetDecoder decoder) + throws CharacterCodingException { + if (!prefixedDataAvailable(prefixLength)) { + throw new BufferUnderflowException(); + } + + int fieldSize = 0; + + switch (prefixLength) { + case 1 : + fieldSize = getUnsigned(); + break; + case 2 : + fieldSize = getUnsignedShort(); + break; + case 4 : + fieldSize = getInt(); + break; + } + + if (fieldSize == 0) { + return ""; + } + + boolean utf16 = decoder.charset().name().startsWith("UTF-16"); + + if (utf16 && (fieldSize & 1) != 0) { + throw new BufferDataException( + "fieldSize is not even for a UTF-16 string."); + } + + int oldLimit = limit(); + int end = position() + fieldSize; + + if (oldLimit < end) { + throw new BufferUnderflowException(); + } + + limit(end); + decoder.reset(); + + int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + + 1; + CharBuffer out = CharBuffer.allocate(expectedLength); + for (;;) { + CoderResult cr; + if (hasRemaining()) { + cr = decoder.decode(buf(), out, true); + } else { + cr = decoder.flush(out); + } + + if (cr.isUnderflow()) { + break; + } + + if (cr.isOverflow()) { + CharBuffer o = CharBuffer + .allocate(out.capacity() + expectedLength); + out.flip(); + o.put(out); + out = o; + continue; + } + + cr.throwException(); + } + + limit(oldLimit); + position(end); + return out.flip().toString(); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putPrefixedString(CharSequence in, CharsetEncoder encoder) + throws CharacterCodingException { + return putPrefixedString(in, 2, 0, encoder); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putPrefixedString(CharSequence in, int prefixLength, + CharsetEncoder encoder) throws CharacterCodingException { + return putPrefixedString(in, prefixLength, 0, encoder); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putPrefixedString(CharSequence in, int prefixLength, + int padding, CharsetEncoder encoder) + throws CharacterCodingException { + return putPrefixedString(in, prefixLength, padding, (byte) 0, encoder); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putPrefixedString(CharSequence val, int prefixLength, + int padding, byte padValue, CharsetEncoder encoder) + throws CharacterCodingException { + int maxLength; + switch (prefixLength) { + case 1 : + maxLength = 255; + break; + case 2 : + maxLength = 65535; + break; + case 4 : + maxLength = Integer.MAX_VALUE; + break; + default : + throw new IllegalArgumentException( + "prefixLength: " + prefixLength); + } + + if (val.length() > maxLength) { + throw new IllegalArgumentException( + "The specified string is too long."); + } + if (val.length() == 0) { + switch (prefixLength) { + case 1 : + put((byte) 0); + break; + case 2 : + putShort((short) 0); + break; + case 4 : + putInt(0); + break; + } + return this; + } + + int padMask; + switch (padding) { + case 0 : + case 1 : + padMask = 0; + break; + case 2 : + padMask = 1; + break; + case 4 : + padMask = 3; + break; + default : + throw new IllegalArgumentException("padding: " + padding); + } + + CharBuffer in = CharBuffer.wrap(val); + skip(prefixLength); // make a room for the length field + int oldPos = position(); + encoder.reset(); + + int expandedState = 0; + + for (;;) { + CoderResult cr; + if (in.hasRemaining()) { + cr = encoder.encode(in, buf(), true); + } else { + cr = encoder.flush(buf()); + } + + if (position() - oldPos > maxLength) { + throw new IllegalArgumentException( + "The specified string is too long."); + } + + if (cr.isUnderflow()) { + break; + } + if (cr.isOverflow()) { + if (isAutoExpand()) { + switch (expandedState) { + case 0 : + autoExpand((int) Math.ceil(in.remaining() + * encoder.averageBytesPerChar())); + expandedState++; + break; + case 1 : + autoExpand((int) Math.ceil(in.remaining() + * encoder.maxBytesPerChar())); + expandedState++; + break; + default : + throw new RuntimeException("Expanded by " + + (int) Math.ceil(in.remaining() + * encoder.maxBytesPerChar()) + + " but that wasn't enough for '" + val + + "'"); + } + continue; + } + } else { + expandedState = 0; + } + cr.throwException(); + } + + // Write the length field + fill(padValue, padding - (position() - oldPos & padMask)); + int length = position() - oldPos; + switch (prefixLength) { + case 1 : + put(oldPos - 1, (byte) length); + break; + case 2 : + putShort(oldPos - 2, (short) length); + break; + case 4 : + putInt(oldPos - 4, length); + break; + } + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public Object getObject() throws ClassNotFoundException { + return getObject(Thread.currentThread().getContextClassLoader()); + } + + /** + * {@inheritDoc} + */ + @Override + public Object getObject(final ClassLoader classLoader) + throws ClassNotFoundException { + if (!prefixedDataAvailable(4)) { + throw new BufferUnderflowException(); + } + + int length = getInt(); + if (length <= 4) { + throw new BufferDataException( + "Object length should be greater than 4: " + length); + } + + int oldLimit = limit(); + limit(position() + length); + try { + ObjectInputStream in = new ObjectInputStream(asInputStream()) { + @Override + protected ObjectStreamClass readClassDescriptor() + throws IOException, ClassNotFoundException { + int type = read(); + if (type < 0) { + throw new EOFException(); + } + switch (type) { + case 0 : // Primitive types + return super.readClassDescriptor(); + case 1 : // Non-primitive types + String className = readUTF(); + Class clazz = Class.forName(className, true, + classLoader); + return ObjectStreamClass.lookup(clazz); + default : + throw new StreamCorruptedException( + "Unexpected class descriptor type: " + + type); + } + } + + @Override + protected Class resolveClass(ObjectStreamClass desc) + throws IOException, ClassNotFoundException { + String name = desc.getName(); + try { + return Class.forName(name, false, classLoader); + } catch (ClassNotFoundException ex) { + return super.resolveClass(desc); + } + } + }; + return in.readObject(); + } catch (IOException e) { + throw new BufferDataException(e); + } finally { + limit(oldLimit); + } + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putObject(Object o) { + int oldPos = position(); + skip(4); // Make a room for the length field. + try { + ObjectOutputStream out = new ObjectOutputStream(asOutputStream()) { + @Override + protected void writeClassDescriptor(ObjectStreamClass desc) + throws IOException { + if (desc.forClass().isPrimitive()) { + write(0); + super.writeClassDescriptor(desc); + } else { + write(1); + writeUTF(desc.getName()); + } + } + }; + out.writeObject(o); + out.flush(); + } catch (IOException e) { + throw new BufferDataException(e); + } + + // Fill the length field + int newPos = position(); + position(oldPos); + putInt(newPos - oldPos - 4); + position(newPos); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean prefixedDataAvailable(int prefixLength) { + return prefixedDataAvailable(prefixLength, Integer.MAX_VALUE); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean prefixedDataAvailable(int prefixLength, int maxDataLength) { + if (remaining() < prefixLength) { + return false; + } + + int dataLength; + switch (prefixLength) { + case 1 : + dataLength = getUnsigned(position()); + break; + case 2 : + dataLength = getUnsignedShort(position()); + break; + case 4 : + dataLength = getInt(position()); + break; + default : + throw new IllegalArgumentException( + "prefixLength: " + prefixLength); + } + + if (dataLength < 0 || dataLength > maxDataLength) { + throw new BufferDataException("dataLength: " + dataLength); + } + + return remaining() - prefixLength >= dataLength; + } + + /** + * {@inheritDoc} + */ + @Override + public int indexOf(byte b) { + if (hasArray()) { + int arrayOffset = arrayOffset(); + int beginPos = arrayOffset + position(); + int limit = arrayOffset + limit(); + byte[] array = array(); + + for (int i = beginPos; i < limit; i++) { + if (array[i] == b) { + return i - arrayOffset; + } + } + } else { + int beginPos = position(); + int limit = limit(); + + for (int i = beginPos; i < limit; i++) { + if (get(i) == b) { + return i; + } + } + } + + return -1; + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer skip(int size) { + autoExpand(size); + return position(position() + size); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer fill(byte value, int size) { + autoExpand(size); + int q = size >>> 3; + int r = size & 7; + + if (q > 0) { + int intValue = value | value << 8 | value << 16 | value << 24; + long longValue = intValue; + longValue <<= 32; + longValue |= intValue; + + for (int i = q; i > 0; i--) { + putLong(longValue); + } + } + + q = r >>> 2; + r = r & 3; + + if (q > 0) { + int intValue = value | value << 8 | value << 16 | value << 24; + putInt(intValue); + } + + q = r >> 1; + r = r & 1; + + if (q > 0) { + short shortValue = (short) (value | value << 8); + putShort(shortValue); + } + + if (r > 0) { + put(value); + } + + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer fillAndReset(byte value, int size) { + autoExpand(size); + int pos = position(); + try { + fill(value, size); + } finally { + position(pos); + } + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer fill(int size) { + autoExpand(size); + int q = size >>> 3; + int r = size & 7; + + for (int i = q; i > 0; i--) { + putLong(0L); + } + + q = r >>> 2; + r = r & 3; + + if (q > 0) { + putInt(0); + } + + q = r >> 1; + r = r & 1; + + if (q > 0) { + putShort((short) 0); + } + + if (r > 0) { + put((byte) 0); + } + + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer fillAndReset(int size) { + autoExpand(size); + int pos = position(); + try { + fill(size); + } finally { + position(pos); + } + + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public > E getEnum(Class enumClass) { + return toEnum(enumClass, getUnsigned()); + } + + /** + * {@inheritDoc} + */ + @Override + public > E getEnum(int index, Class enumClass) { + return toEnum(enumClass, getUnsigned(index)); + } + + /** + * {@inheritDoc} + */ + @Override + public > E getEnumShort(Class enumClass) { + return toEnum(enumClass, getUnsignedShort()); + } + + /** + * {@inheritDoc} + */ + @Override + public > E getEnumShort(int index, Class enumClass) { + return toEnum(enumClass, getUnsignedShort(index)); + } + + /** + * {@inheritDoc} + */ + @Override + public > E getEnumInt(Class enumClass) { + return toEnum(enumClass, getInt()); + } + + /** + * {@inheritDoc} + */ + @Override + public > E getEnumInt(int index, Class enumClass) { + return toEnum(enumClass, getInt(index)); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putEnum(Enum e) { + if (e.ordinal() > BYTE_MASK) { + throw new IllegalArgumentException( + enumConversionErrorMessage(e, "byte")); + } + return put((byte) e.ordinal()); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putEnum(int index, Enum e) { + if (e.ordinal() > BYTE_MASK) { + throw new IllegalArgumentException( + enumConversionErrorMessage(e, "byte")); + } + return put(index, (byte) e.ordinal()); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putEnumShort(Enum e) { + if (e.ordinal() > SHORT_MASK) { + throw new IllegalArgumentException( + enumConversionErrorMessage(e, "short")); + } + return putShort((short) e.ordinal()); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putEnumShort(int index, Enum e) { + if (e.ordinal() > SHORT_MASK) { + throw new IllegalArgumentException( + enumConversionErrorMessage(e, "short")); + } + return putShort(index, (short) e.ordinal()); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putEnumInt(Enum e) { + return putInt(e.ordinal()); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putEnumInt(int index, Enum e) { + return putInt(index, e.ordinal()); + } + + private E toEnum(Class enumClass, int i) { + E[] enumConstants = enumClass.getEnumConstants(); + if (i > enumConstants.length) { + throw new IndexOutOfBoundsException(String.format( + "%d is too large of an ordinal to convert to the enum %s", + i, enumClass.getName())); + } + return enumConstants[i]; + } + + private String enumConversionErrorMessage(Enum e, String type) { + return String.format("%s.%s has an ordinal value too large for a %s", + e.getClass().getName(), e.name(), type); + } + + /** + * {@inheritDoc} + */ + @Override + public > EnumSet getEnumSet(Class enumClass) { + return toEnumSet(enumClass, get() & BYTE_MASK); + } + + /** + * {@inheritDoc} + */ + @Override + public > EnumSet getEnumSet(int index, + Class enumClass) { + return toEnumSet(enumClass, get(index) & BYTE_MASK); + } + + /** + * {@inheritDoc} + */ + @Override + public > EnumSet getEnumSetShort(Class enumClass) { + return toEnumSet(enumClass, getShort() & SHORT_MASK); + } + + /** + * {@inheritDoc} + */ + @Override + public > EnumSet getEnumSetShort(int index, + Class enumClass) { + return toEnumSet(enumClass, getShort(index) & SHORT_MASK); + } + + /** + * {@inheritDoc} + */ + @Override + public > EnumSet getEnumSetInt(Class enumClass) { + return toEnumSet(enumClass, getInt() & INT_MASK); + } + + /** + * {@inheritDoc} + */ + @Override + public > EnumSet getEnumSetInt(int index, + Class enumClass) { + return toEnumSet(enumClass, getInt(index) & INT_MASK); + } + + /** + * {@inheritDoc} + */ + @Override + public > EnumSet getEnumSetLong(Class enumClass) { + return toEnumSet(enumClass, getLong()); + } + + /** + * {@inheritDoc} + */ + @Override + public > EnumSet getEnumSetLong(int index, + Class enumClass) { + return toEnumSet(enumClass, getLong(index)); + } + + private > EnumSet toEnumSet(Class clazz, + long vector) { + EnumSet set = EnumSet.noneOf(clazz); + long mask = 1; + for (E e : clazz.getEnumConstants()) { + if ((mask & vector) == mask) { + set.add(e); + } + mask <<= 1; + } + return set; + } + + /** + * {@inheritDoc} + */ + @Override + public > IoBuffer putEnumSet(Set set) { + long vector = toLong(set); + if ((vector & ~BYTE_MASK) != 0) { + throw new IllegalArgumentException( + "The enum set is too large to fit in a byte: " + set); + } + return put((byte) vector); + } + + /** + * {@inheritDoc} + */ + @Override + public > IoBuffer putEnumSet(int index, Set set) { + long vector = toLong(set); + if ((vector & ~BYTE_MASK) != 0) { + throw new IllegalArgumentException( + "The enum set is too large to fit in a byte: " + set); + } + return put(index, (byte) vector); + } + + /** + * {@inheritDoc} + */ + @Override + public > IoBuffer putEnumSetShort(Set set) { + long vector = toLong(set); + if ((vector & ~SHORT_MASK) != 0) { + throw new IllegalArgumentException( + "The enum set is too large to fit in a short: " + set); + } + return putShort((short) vector); + } + + /** + * {@inheritDoc} + */ + @Override + public > IoBuffer putEnumSetShort(int index, Set set) { + long vector = toLong(set); + if ((vector & ~SHORT_MASK) != 0) { + throw new IllegalArgumentException( + "The enum set is too large to fit in a short: " + set); + } + return putShort(index, (short) vector); + } + + /** + * {@inheritDoc} + */ + @Override + public > IoBuffer putEnumSetInt(Set set) { + long vector = toLong(set); + if ((vector & ~INT_MASK) != 0) { + throw new IllegalArgumentException( + "The enum set is too large to fit in an int: " + set); + } + return putInt((int) vector); + } + + /** + * {@inheritDoc} + */ + @Override + public > IoBuffer putEnumSetInt(int index, Set set) { + long vector = toLong(set); + if ((vector & ~INT_MASK) != 0) { + throw new IllegalArgumentException( + "The enum set is too large to fit in an int: " + set); + } + return putInt(index, (int) vector); + } + + /** + * {@inheritDoc} + */ + @Override + public > IoBuffer putEnumSetLong(Set set) { + return putLong(toLong(set)); + } + + /** + * {@inheritDoc} + */ + @Override + public > IoBuffer putEnumSetLong(int index, Set set) { + return putLong(index, toLong(set)); + } + + private > long toLong(Set set) { + long vector = 0; + for (E e : set) { + if (e.ordinal() >= Long.SIZE) { + throw new IllegalArgumentException( + "The enum set is too large to fit in a bit vector: " + + set); + } + vector |= 1L << e.ordinal(); + } + return vector; + } + + /** + * This method forwards the call to {@link #expand(int)} only when + * autoExpand property is true. + */ + private IoBuffer autoExpand(int expectedRemaining) { + if (isAutoExpand()) { + expand(expectedRemaining, true); + } + return this; + } + + /** + * This method forwards the call to {@link #expand(int)} only when + * autoExpand property is true. + */ + private IoBuffer autoExpand(int pos, int expectedRemaining) { + if (isAutoExpand()) { + expand(pos, expectedRemaining, true); + } + return this; + } + + private static void checkFieldSize(int fieldSize) { + if (fieldSize < 0) { + throw new IllegalArgumentException( + "fieldSize cannot be negative: " + fieldSize); + } + } } diff --git a/src/main/java/com/google/code/yanf4j/buffer/BufferDataException.java b/src/main/java/com/google/code/yanf4j/buffer/BufferDataException.java index eabca4a96..3a6048620 100644 --- a/src/main/java/com/google/code/yanf4j/buffer/BufferDataException.java +++ b/src/main/java/com/google/code/yanf4j/buffer/BufferDataException.java @@ -29,26 +29,22 @@ * */ public class BufferDataException extends RuntimeException { - private static final long serialVersionUID = -4138189188602563502L; + private static final long serialVersionUID = -4138189188602563502L; + public BufferDataException() { + super(); + } - public BufferDataException() { - super(); - } + public BufferDataException(String message) { + super(message); + } + public BufferDataException(String message, Throwable cause) { + super(message, cause); + } - public BufferDataException(String message) { - super(message); - } - - - public BufferDataException(String message, Throwable cause) { - super(message, cause); - } - - - public BufferDataException(Throwable cause) { - super(cause); - } + public BufferDataException(Throwable cause) { + super(cause); + } } diff --git a/src/main/java/com/google/code/yanf4j/buffer/CachedBufferAllocator.java b/src/main/java/com/google/code/yanf4j/buffer/CachedBufferAllocator.java index 275097bac..8e1bc8b97 100644 --- a/src/main/java/com/google/code/yanf4j/buffer/CachedBufferAllocator.java +++ b/src/main/java/com/google/code/yanf4j/buffer/CachedBufferAllocator.java @@ -27,9 +27,6 @@ import com.google.code.yanf4j.util.CircularQueue; - - - /** * An {@link IoBufferAllocator} that caches the buffers which are likely to be * reused during auto-expansion of the buffers. @@ -64,251 +61,235 @@ */ public class CachedBufferAllocator implements IoBufferAllocator { - private static final int DEFAULT_MAX_POOL_SIZE = 8; - private static final int DEFAULT_MAX_CACHED_BUFFER_SIZE = 1 << 18; // 256KB - - private final int maxPoolSize; - private final int maxCachedBufferSize; - - private final ThreadLocal>> heapBuffers; - private final ThreadLocal>> directBuffers; - - - /** - * Creates a new instance with the default parameters ({@literal - * #DEFAULT_MAX_POOL_SIZE} and {@literal #DEFAULT_MAX_CACHED_BUFFER_SIZE}). - */ - public CachedBufferAllocator() { - this(DEFAULT_MAX_POOL_SIZE, DEFAULT_MAX_CACHED_BUFFER_SIZE); - } - - - /** - * Creates a new instance. - * - * @param maxPoolSize - * the maximum number of buffers with the same capacity per - * thread. 0 disables this limitation. - * @param maxCachedBufferSize - * the maximum capacity of a cached buffer. A buffer whose - * capacity is bigger than this value is not pooled. 0 - * disables this limitation. - */ - public CachedBufferAllocator(int maxPoolSize, int maxCachedBufferSize) { - if (maxPoolSize < 0) { - throw new IllegalArgumentException("maxPoolSize: " + maxPoolSize); - } - if (maxCachedBufferSize < 0) { - throw new IllegalArgumentException("maxCachedBufferSize: " + maxCachedBufferSize); - } - - this.maxPoolSize = maxPoolSize; - this.maxCachedBufferSize = maxCachedBufferSize; - - this.heapBuffers = new ThreadLocal>>() { - @Override - protected Map> initialValue() { - return newPoolMap(); - } - }; - this.directBuffers = new ThreadLocal>>() { - @Override - protected Map> initialValue() { - return newPoolMap(); - } - }; - } - - - /** - * Returns the maximum number of buffers with the same capacity per thread. - * 0 means 'no limitation'. - */ - public int getMaxPoolSize() { - return this.maxPoolSize; - } - - - /** - * Returns the maximum capacity of a cached buffer. A buffer whose capacity - * is bigger than this value is not pooled. 0 means 'no - * limitation'. - */ - public int getMaxCachedBufferSize() { - return this.maxCachedBufferSize; - } - - - private Map> newPoolMap() { - Map> poolMap = new HashMap>(); - int poolSize = this.maxPoolSize == 0 ? DEFAULT_MAX_POOL_SIZE : this.maxPoolSize; - for (int i = 0; i < 31; i++) { - poolMap.put(1 << i, new CircularQueue(poolSize)); - } - poolMap.put(0, new CircularQueue(poolSize)); - poolMap.put(Integer.MAX_VALUE, new CircularQueue(poolSize)); - return poolMap; - } - - - public IoBuffer allocate(int requestedCapacity, boolean direct) { - int actualCapacity = IoBuffer.normalizeCapacity(requestedCapacity); - IoBuffer buf; - if (this.maxCachedBufferSize != 0 && actualCapacity > this.maxCachedBufferSize) { - if (direct) { - buf = wrap(ByteBuffer.allocateDirect(actualCapacity)); - } - else { - buf = wrap(ByteBuffer.allocate(actualCapacity)); - } - } - else { - Queue pool; - if (direct) { - pool = this.directBuffers.get().get(actualCapacity); - } - else { - pool = this.heapBuffers.get().get(actualCapacity); - } - - // Recycle if possible. - buf = pool.poll(); - if (buf != null) { - buf.clear(); - buf.setAutoExpand(false); - buf.order(ByteOrder.BIG_ENDIAN); - } - else { - if (direct) { - buf = wrap(ByteBuffer.allocateDirect(actualCapacity)); - } - else { - buf = wrap(ByteBuffer.allocate(actualCapacity)); - } - } - } - - buf.limit(requestedCapacity); - return buf; - } - - - public ByteBuffer allocateNioBuffer(int capacity, boolean direct) { - return allocate(capacity, direct).buf(); - } - - - public IoBuffer wrap(ByteBuffer nioBuffer) { - return new CachedBuffer(nioBuffer); - } - - - public void dispose() { - } - - private class CachedBuffer extends AbstractIoBuffer { - private final Thread ownerThread; - private ByteBuffer buf; - - - protected CachedBuffer(ByteBuffer buf) { - super(CachedBufferAllocator.this, buf.capacity()); - this.ownerThread = Thread.currentThread(); - this.buf = buf; - buf.order(ByteOrder.BIG_ENDIAN); - } - - - protected CachedBuffer(CachedBuffer parent, ByteBuffer buf) { - super(parent); - this.ownerThread = Thread.currentThread(); - this.buf = buf; - } - - - @Override - public ByteBuffer buf() { - if (this.buf == null) { - throw new IllegalStateException("Buffer has been freed already."); - } - return this.buf; - } - - - @Override - protected void buf(ByteBuffer buf) { - ByteBuffer oldBuf = this.buf; - this.buf = buf; - free(oldBuf); - } - - - @Override - protected IoBuffer duplicate0() { - return new CachedBuffer(this, buf().duplicate()); - } - - - @Override - protected IoBuffer slice0() { - return new CachedBuffer(this, buf().slice()); - } - - - @Override - protected IoBuffer asReadOnlyBuffer0() { - return new CachedBuffer(this, buf().asReadOnlyBuffer()); - } - - - @Override - public byte[] array() { - return buf().array(); - } - - - @Override - public int arrayOffset() { - return buf().arrayOffset(); - } - - - @Override - public boolean hasArray() { - return buf().hasArray(); - } - - - @Override - public void free() { - free(this.buf); - this.buf = null; - } - - - private void free(ByteBuffer oldBuf) { - if (oldBuf == null || oldBuf.capacity() > CachedBufferAllocator.this.maxCachedBufferSize || oldBuf.isReadOnly() || isDerived() - || Thread.currentThread() != this.ownerThread) { - return; - } - - // Add to the cache. - Queue pool; - if (oldBuf.isDirect()) { - pool = CachedBufferAllocator.this.directBuffers.get().get(oldBuf.capacity()); - } - else { - pool = CachedBufferAllocator.this.heapBuffers.get().get(oldBuf.capacity()); - } - - if (pool == null) { - return; - } - - // Restrict the size of the pool to prevent OOM. - if (CachedBufferAllocator.this.maxPoolSize == 0 || pool.size() < CachedBufferAllocator.this.maxPoolSize) { - pool.offer(new CachedBuffer(oldBuf)); - } - } - } + private static final int DEFAULT_MAX_POOL_SIZE = 8; + private static final int DEFAULT_MAX_CACHED_BUFFER_SIZE = 1 << 18; // 256KB + + private final int maxPoolSize; + private final int maxCachedBufferSize; + + private final ThreadLocal>> heapBuffers; + private final ThreadLocal>> directBuffers; + + /** + * Creates a new instance with the default parameters ({@literal + * #DEFAULT_MAX_POOL_SIZE} and {@literal #DEFAULT_MAX_CACHED_BUFFER_SIZE}). + */ + public CachedBufferAllocator() { + this(DEFAULT_MAX_POOL_SIZE, DEFAULT_MAX_CACHED_BUFFER_SIZE); + } + + /** + * Creates a new instance. + * + * @param maxPoolSize + * the maximum number of buffers with the same capacity per + * thread. 0 disables this limitation. + * @param maxCachedBufferSize + * the maximum capacity of a cached buffer. A buffer whose + * capacity is bigger than this value is not pooled. 0 + * disables this limitation. + */ + public CachedBufferAllocator(int maxPoolSize, int maxCachedBufferSize) { + if (maxPoolSize < 0) { + throw new IllegalArgumentException("maxPoolSize: " + maxPoolSize); + } + if (maxCachedBufferSize < 0) { + throw new IllegalArgumentException( + "maxCachedBufferSize: " + maxCachedBufferSize); + } + + this.maxPoolSize = maxPoolSize; + this.maxCachedBufferSize = maxCachedBufferSize; + + this.heapBuffers = new ThreadLocal>>() { + @Override + protected Map> initialValue() { + return newPoolMap(); + } + }; + this.directBuffers = new ThreadLocal>>() { + @Override + protected Map> initialValue() { + return newPoolMap(); + } + }; + } + + /** + * Returns the maximum number of buffers with the same capacity per thread. + * 0 means 'no limitation'. + */ + public int getMaxPoolSize() { + return this.maxPoolSize; + } + + /** + * Returns the maximum capacity of a cached buffer. A buffer whose capacity + * is bigger than this value is not pooled. 0 means 'no + * limitation'. + */ + public int getMaxCachedBufferSize() { + return this.maxCachedBufferSize; + } + + private Map> newPoolMap() { + Map> poolMap = new HashMap>(); + int poolSize = this.maxPoolSize == 0 + ? DEFAULT_MAX_POOL_SIZE + : this.maxPoolSize; + for (int i = 0; i < 31; i++) { + poolMap.put(1 << i, new CircularQueue(poolSize)); + } + poolMap.put(0, new CircularQueue(poolSize)); + poolMap.put(Integer.MAX_VALUE, + new CircularQueue(poolSize)); + return poolMap; + } + + public IoBuffer allocate(int requestedCapacity, boolean direct) { + int actualCapacity = IoBuffer.normalizeCapacity(requestedCapacity); + IoBuffer buf; + if (this.maxCachedBufferSize != 0 + && actualCapacity > this.maxCachedBufferSize) { + if (direct) { + buf = wrap(ByteBuffer.allocateDirect(actualCapacity)); + } else { + buf = wrap(ByteBuffer.allocate(actualCapacity)); + } + } else { + Queue pool; + if (direct) { + pool = this.directBuffers.get().get(actualCapacity); + } else { + pool = this.heapBuffers.get().get(actualCapacity); + } + + // Recycle if possible. + buf = pool.poll(); + if (buf != null) { + buf.clear(); + buf.setAutoExpand(false); + buf.order(ByteOrder.BIG_ENDIAN); + } else { + if (direct) { + buf = wrap(ByteBuffer.allocateDirect(actualCapacity)); + } else { + buf = wrap(ByteBuffer.allocate(actualCapacity)); + } + } + } + + buf.limit(requestedCapacity); + return buf; + } + + public ByteBuffer allocateNioBuffer(int capacity, boolean direct) { + return allocate(capacity, direct).buf(); + } + + public IoBuffer wrap(ByteBuffer nioBuffer) { + return new CachedBuffer(nioBuffer); + } + + public void dispose() { + } + + private class CachedBuffer extends AbstractIoBuffer { + private final Thread ownerThread; + private ByteBuffer buf; + + protected CachedBuffer(ByteBuffer buf) { + super(CachedBufferAllocator.this, buf.capacity()); + this.ownerThread = Thread.currentThread(); + this.buf = buf; + buf.order(ByteOrder.BIG_ENDIAN); + } + + protected CachedBuffer(CachedBuffer parent, ByteBuffer buf) { + super(parent); + this.ownerThread = Thread.currentThread(); + this.buf = buf; + } + + @Override + public ByteBuffer buf() { + if (this.buf == null) { + throw new IllegalStateException( + "Buffer has been freed already."); + } + return this.buf; + } + + @Override + protected void buf(ByteBuffer buf) { + ByteBuffer oldBuf = this.buf; + this.buf = buf; + free(oldBuf); + } + + @Override + protected IoBuffer duplicate0() { + return new CachedBuffer(this, buf().duplicate()); + } + + @Override + protected IoBuffer slice0() { + return new CachedBuffer(this, buf().slice()); + } + + @Override + protected IoBuffer asReadOnlyBuffer0() { + return new CachedBuffer(this, buf().asReadOnlyBuffer()); + } + + @Override + public byte[] array() { + return buf().array(); + } + + @Override + public int arrayOffset() { + return buf().arrayOffset(); + } + + @Override + public boolean hasArray() { + return buf().hasArray(); + } + + @Override + public void free() { + free(this.buf); + this.buf = null; + } + + private void free(ByteBuffer oldBuf) { + if (oldBuf == null || oldBuf + .capacity() > CachedBufferAllocator.this.maxCachedBufferSize + || oldBuf.isReadOnly() || isDerived() + || Thread.currentThread() != this.ownerThread) { + return; + } + + // Add to the cache. + Queue pool; + if (oldBuf.isDirect()) { + pool = CachedBufferAllocator.this.directBuffers.get() + .get(oldBuf.capacity()); + } else { + pool = CachedBufferAllocator.this.heapBuffers.get() + .get(oldBuf.capacity()); + } + + if (pool == null) { + return; + } + + // Restrict the size of the pool to prevent OOM. + if (CachedBufferAllocator.this.maxPoolSize == 0 + || pool.size() < CachedBufferAllocator.this.maxPoolSize) { + pool.offer(new CachedBuffer(oldBuf)); + } + } + } } diff --git a/src/main/java/com/google/code/yanf4j/buffer/IoBuffer.java b/src/main/java/com/google/code/yanf4j/buffer/IoBuffer.java index 5794e41f5..96ddb8861 100644 --- a/src/main/java/com/google/code/yanf4j/buffer/IoBuffer.java +++ b/src/main/java/com/google/code/yanf4j/buffer/IoBuffer.java @@ -38,7 +38,6 @@ import java.util.EnumSet; import java.util.Set; - /** * A byte buffer used by MINA applications. *

@@ -48,7 +47,8 @@ *

    *
  • It doesn't provide useful getters and putters such as fill, * get/putString, and get/putAsciiInt() enough.
  • - *
  • It is difficult to write variable-length data due to its fixed capacity
  • + *
  • It is difficult to write variable-length data due to its fixed + * capacity
  • *
*

* @@ -151,1491 +151,1360 @@ * $ */ public abstract class IoBuffer implements Comparable { - /** The allocator used to create new buffers */ - private static IoBufferAllocator allocator = new SimpleBufferAllocator(); - - /** A flag indicating which type of buffer we are using : heap or direct */ - private static boolean useDirectBuffer = false; - - - /** - * Returns the allocator used by existing and new buffers - */ - public static IoBufferAllocator getAllocator() { - return allocator; - } - - - /** - * Sets the allocator used by existing and new buffers - */ - public static void setAllocator(IoBufferAllocator newAllocator) { - if (newAllocator == null) { - throw new NullPointerException("allocator"); - } - - IoBufferAllocator oldAllocator = allocator; - - allocator = newAllocator; - - if (null != oldAllocator) { - oldAllocator.dispose(); - } - } - - - /** - * Returns true if and only if a direct buffer is allocated by - * default when the type of the new buffer is not specified. The default - * value is false. - */ - public static boolean isUseDirectBuffer() { - return useDirectBuffer; - } - - - /** - * Sets if a direct buffer should be allocated by default when the type of - * the new buffer is not specified. The default value is false. - */ - public static void setUseDirectBuffer(boolean useDirectBuffer) { - IoBuffer.useDirectBuffer = useDirectBuffer; - } - - - /** - * Returns the direct or heap buffer which is capable to store the specified - * amount of bytes. - * - * @param capacity - * the capacity of the buffer - * - * @see #setUseDirectBuffer(boolean) - */ - public static IoBuffer allocate(int capacity) { - return allocate(capacity, useDirectBuffer); - } - - - /** - * Returns the buffer which is capable of the specified size. - * - * @param capacity - * the capacity of the buffer - * @param direct - * true to get a direct buffer, false to get a - * heap buffer. - */ - public static IoBuffer allocate(int capacity, boolean direct) { - if (capacity < 0) { - throw new IllegalArgumentException("capacity: " + capacity); - } - - return allocator.allocate(capacity, direct); - } - - - /** - * Wraps the specified NIO {@link ByteBuffer} into MINA buffer. - */ - public static IoBuffer wrap(ByteBuffer nioBuffer) { - return allocator.wrap(nioBuffer); - } - - - /** - * Wraps the specified byte array into MINA heap buffer. - */ - public static IoBuffer wrap(byte[] byteArray) { - return wrap(ByteBuffer.wrap(byteArray)); - } - - - /** - * Wraps the specified byte array into MINA heap buffer. - */ - public static IoBuffer wrap(byte[] byteArray, int offset, int length) { - return wrap(ByteBuffer.wrap(byteArray, offset, length)); - } - - - /** - * Normalizes the specified capacity of the buffer to power of 2, which is - * often helpful for optimal memory usage and performance. If it is greater - * than or equal to {@link Integer#MAX_VALUE}, it returns - * {@link Integer#MAX_VALUE}. If it is zero, it returns zero. - */ - protected static int normalizeCapacity(int requestedCapacity) { - switch (requestedCapacity) { - case 0: - case 1 << 0: - case 1 << 1: - case 1 << 2: - case 1 << 3: - case 1 << 4: - case 1 << 5: - case 1 << 6: - case 1 << 7: - case 1 << 8: - case 1 << 9: - case 1 << 10: - case 1 << 11: - case 1 << 12: - case 1 << 13: - case 1 << 14: - case 1 << 15: - case 1 << 16: - case 1 << 17: - case 1 << 18: - case 1 << 19: - case 1 << 21: - case 1 << 22: - case 1 << 23: - case 1 << 24: - case 1 << 25: - case 1 << 26: - case 1 << 27: - case 1 << 28: - case 1 << 29: - case 1 << 30: - case Integer.MAX_VALUE: - return requestedCapacity; - } - - int newCapacity = 1; - while (newCapacity < requestedCapacity) { - newCapacity <<= 1; - if (newCapacity < 0) { - return Integer.MAX_VALUE; - } - } - return newCapacity; - } - - - /** - * Creates a new instance. This is an empty constructor. - */ - protected IoBuffer() { - } - - - /** - * Declares this buffer and all its derived buffers are not used anymore so - * that it can be reused by some {@link IoBufferAllocator} implementations. - * It is not mandatory to call this method, but you might want to invoke - * this method for maximum performance. - */ - public abstract void free(); - - - /** - * Returns the underlying NIO buffer instance. - */ - public abstract ByteBuffer buf(); - - - /** - * @see ByteBuffer#isDirect() - */ - public abstract boolean isDirect(); - - - /** - * returns true if and only if this buffer is derived from other - * buffer via {@link #duplicate()}, {@link #slice()} or - * {@link #asReadOnlyBuffer()}. - */ - public abstract boolean isDerived(); - - - /** - * @see ByteBuffer#isReadOnly() - */ - public abstract boolean isReadOnly(); - - - /** - * Returns the minimum capacity of this buffer which is used to determine - * the new capacity of the buffer shrunk by {@link #compact()} and - * {@link #shrink()} operation. The default value is the initial capacity of - * the buffer. - */ - public abstract int minimumCapacity(); - - - /** - * Sets the minimum capacity of this buffer which is used to determine the - * new capacity of the buffer shrunk by {@link #compact()} and - * {@link #shrink()} operation. The default value is the initial capacity of - * the buffer. - */ - public abstract IoBuffer minimumCapacity(int minimumCapacity); - - - /** - * @see ByteBuffer#capacity() - */ - public abstract int capacity(); - - - /** - * Increases the capacity of this buffer. If the new capacity is less than - * or equal to the current capacity, this method returns silently. If the - * new capacity is greater than the current capacity, the buffer is - * reallocated while retaining the position, limit, mark and the content of - * the buffer. - */ - public abstract IoBuffer capacity(int newCapacity); - - - /** - * Returns true if and only if autoExpand is turned on. - */ - public abstract boolean isAutoExpand(); - - - /** - * Turns on or off autoExpand. - */ - public abstract IoBuffer setAutoExpand(boolean autoExpand); - - - /** - * Returns true if and only if autoShrink is turned on. - */ - public abstract boolean isAutoShrink(); - - - /** - * Turns on or off autoShrink. - */ - public abstract IoBuffer setAutoShrink(boolean autoShrink); - - - /** - * Changes the capacity and limit of this buffer so this buffer get the - * specified expectedRemaining room from the current position. This - * method works even if you didn't set autoExpand to true. - */ - public abstract IoBuffer expand(int expectedRemaining); - - - /** - * Changes the capacity and limit of this buffer so this buffer get the - * specified expectedRemaining room from the specified - * position. This method works even if you didn't set - * autoExpand to true. - */ - public abstract IoBuffer expand(int position, int expectedRemaining); - - - /** - * Changes the capacity of this buffer so this buffer occupies as less - * memory as possible while retaining the position, limit and the buffer - * content between the position and limit. The capacity of the buffer never - * becomes less than {@link #minimumCapacity()}. The mark is discarded once - * the capacity changes. - */ - public abstract IoBuffer shrink(); - - - /** - * @see java.nio.Buffer#position() - */ - public abstract int position(); - - - /** - * @see java.nio.Buffer#position(int) - */ - public abstract IoBuffer position(int newPosition); - - - /** - * @see java.nio.Buffer#limit() - */ - public abstract int limit(); - - - /** - * @see java.nio.Buffer#limit(int) - */ - public abstract IoBuffer limit(int newLimit); - - - /** - * @see java.nio.Buffer#mark() - */ - public abstract IoBuffer mark(); - - - /** - * Returns the position of the current mark. This method returns -1 - * if no mark is set. - */ - public abstract int markValue(); - - - /** - * @see java.nio.Buffer#reset() - */ - public abstract IoBuffer reset(); - - - /** - * @see java.nio.Buffer#clear() - */ - public abstract IoBuffer clear(); - - - /** - * Clears this buffer and fills its content with NUL. The position - * is set to zero, the limit is set to the capacity, and the mark is - * discarded. - */ - public abstract IoBuffer sweep(); - - - /** - * double Clears this buffer and fills its content with value. The - * position is set to zero, the limit is set to the capacity, and the mark - * is discarded. - */ - public abstract IoBuffer sweep(byte value); - - - /** - * @see java.nio.Buffer#flip() - */ - public abstract IoBuffer flip(); - - - /** - * @see java.nio.Buffer#rewind() - */ - public abstract IoBuffer rewind(); - - - /** - * @see java.nio.Buffer#remaining() - */ - public abstract int remaining(); - - - /** - * @see java.nio.Buffer#hasRemaining() - */ - public abstract boolean hasRemaining(); - - - /** - * @see ByteBuffer#duplicate() - */ - public abstract IoBuffer duplicate(); - - - /** - * @see ByteBuffer#slice() - */ - public abstract IoBuffer slice(); - - - /** - * @see ByteBuffer#asReadOnlyBuffer() - */ - public abstract IoBuffer asReadOnlyBuffer(); - - - /** - * @see ByteBuffer#hasArray() - */ - public abstract boolean hasArray(); - - - /** - * @see ByteBuffer#array() - */ - public abstract byte[] array(); - - - /** - * @see ByteBuffer#arrayOffset() - */ - public abstract int arrayOffset(); - - - /** - * @see ByteBuffer#get() - */ - public abstract byte get(); - - - /** - * Reads one unsigned byte as a short integer. - */ - public abstract short getUnsigned(); - - - /** - * @see ByteBuffer#put(byte) - */ - public abstract IoBuffer put(byte b); - - - /** - * @see ByteBuffer#get(int) - */ - public abstract byte get(int index); - - - /** - * Reads one byte as an unsigned short integer. - */ - public abstract short getUnsigned(int index); - - - /** - * @see ByteBuffer#put(int, byte) - */ - public abstract IoBuffer put(int index, byte b); - - - /** - * @see ByteBuffer#get(byte[], int, int) - */ - public abstract IoBuffer get(byte[] dst, int offset, int length); - - - /** - * @see ByteBuffer#get(byte[]) - */ - public abstract IoBuffer get(byte[] dst); - - - /** - * TODO document me. - */ - public abstract IoBuffer getSlice(int index, int length); - - - /** - * TODO document me. - */ - public abstract IoBuffer getSlice(int length); - - - /** - * Writes the content of the specified src into this buffer. - */ - public abstract IoBuffer put(ByteBuffer src); - - - /** - * Writes the content of the specified src into this buffer. - */ - public abstract IoBuffer put(IoBuffer src); - - - /** - * @see ByteBuffer#put(byte[], int, int) - */ - public abstract IoBuffer put(byte[] src, int offset, int length); - - - /** - * @see ByteBuffer#put(byte[]) - */ - public abstract IoBuffer put(byte[] src); - - - /** - * @see ByteBuffer#compact() - */ - public abstract IoBuffer compact(); - - - /** - * @see ByteBuffer#order() - */ - public abstract ByteOrder order(); - - - /** - * @see ByteBuffer#order(ByteOrder) - */ - public abstract IoBuffer order(ByteOrder bo); - - - /** - * @see ByteBuffer#getChar() - */ - public abstract char getChar(); - - - /** - * @see ByteBuffer#putChar(char) - */ - public abstract IoBuffer putChar(char value); - - - /** - * @see ByteBuffer#getChar(int) - */ - public abstract char getChar(int index); - - - /** - * @see ByteBuffer#putChar(int, char) - */ - public abstract IoBuffer putChar(int index, char value); - - - /** - * @see ByteBuffer#asCharBuffer() - */ - public abstract CharBuffer asCharBuffer(); - - - /** - * @see ByteBuffer#getShort() - */ - public abstract short getShort(); - - - /** - * Reads two bytes unsigned integer. - */ - public abstract int getUnsignedShort(); - - - /** - * @see ByteBuffer#putShort(short) - */ - public abstract IoBuffer putShort(short value); - - - /** - * @see ByteBuffer#getShort() - */ - public abstract short getShort(int index); - - - /** - * Reads two bytes unsigned integer. - */ - public abstract int getUnsignedShort(int index); - - - /** - * @see ByteBuffer#putShort(int, short) - */ - public abstract IoBuffer putShort(int index, short value); - - - /** - * @see ByteBuffer#asShortBuffer() - */ - public abstract ShortBuffer asShortBuffer(); - - - /** - * @see ByteBuffer#getInt() - */ - public abstract int getInt(); - - - /** - * Reads four bytes unsigned integer. - */ - public abstract long getUnsignedInt(); - - - /** - * Relative get method for reading a medium int value. - * - *

- * Reads the next three bytes at this buffer's current position, composing - * them into an int value according to the current byte order, and then - * increments the position by three. - *

- * - * @return The medium int value at the buffer's current position - */ - public abstract int getMediumInt(); - - - /** - * Relative get method for reading an unsigned medium int value. - * - *

- * Reads the next three bytes at this buffer's current position, composing - * them into an int value according to the current byte order, and then - * increments the position by three. - *

- * - * @return The unsigned medium int value at the buffer's current position - */ - public abstract int getUnsignedMediumInt(); - - - /** - * Absolute get method for reading a medium int value. - * - *

- * Reads the next three bytes at this buffer's current position, composing - * them into an int value according to the current byte order. - *

- * - * @param index - * The index from which the medium int will be read - * @return The medium int value at the given index - * - * @throws IndexOutOfBoundsException - * If index is negative or not smaller than the - * buffer's limit - */ - public abstract int getMediumInt(int index); - - - /** - * Absolute get method for reading an unsigned medium int value. - * - *

- * Reads the next three bytes at this buffer's current position, composing - * them into an int value according to the current byte order. - *

- * - * @param index - * The index from which the unsigned medium int will be read - * @return The unsigned medium int value at the given index - * - * @throws IndexOutOfBoundsException - * If index is negative or not smaller than the - * buffer's limit - */ - public abstract int getUnsignedMediumInt(int index); - - - /** - * Relative put method for writing a medium int value. - * - *

- * Writes three bytes containing the given int value, in the current byte - * order, into this buffer at the current position, and then increments the - * position by three. - *

- * - * @param value - * The medium int value to be written - * - * @return This buffer - * - * @throws BufferOverflowException - * If there are fewer than three bytes remaining in this buffer - * - * @throws ReadOnlyBufferException - * If this buffer is read-only - */ - public abstract IoBuffer putMediumInt(int value); - - - /** - * Absolute put method for writing a medium int value. - * - *

- * Writes three bytes containing the given int value, in the current byte - * order, into this buffer at the given index. - *

- * - * @param index - * The index at which the bytes will be written - * - * @param value - * The medium int value to be written - * - * @return This buffer - * - * @throws IndexOutOfBoundsException - * If index is negative or not smaller than the - * buffer's limit, minus three - * - * @throws ReadOnlyBufferException - * If this buffer is read-only - */ - public abstract IoBuffer putMediumInt(int index, int value); - - - /** - * @see ByteBuffer#putInt(int) - */ - public abstract IoBuffer putInt(int value); - - - /** - * @see ByteBuffer#getInt(int) - */ - public abstract int getInt(int index); - - - /** - * Reads four bytes unsigned integer. - */ - public abstract long getUnsignedInt(int index); - - - /** - * @see ByteBuffer#putInt(int, int) - */ - public abstract IoBuffer putInt(int index, int value); - - - /** - * @see ByteBuffer#asIntBuffer() - */ - public abstract IntBuffer asIntBuffer(); - - - /** - * @see ByteBuffer#getLong() - */ - public abstract long getLong(); - - - /** - * @see ByteBuffer#putLong(int, long) - */ - public abstract IoBuffer putLong(long value); - - - /** - * @see ByteBuffer#getLong(int) - */ - public abstract long getLong(int index); - - - /** - * @see ByteBuffer#putLong(int, long) - */ - public abstract IoBuffer putLong(int index, long value); - - - /** - * @see ByteBuffer#asLongBuffer() - */ - public abstract LongBuffer asLongBuffer(); - - - /** - * @see ByteBuffer#getFloat() - */ - public abstract float getFloat(); - - - /** - * @see ByteBuffer#putFloat(float) - */ - public abstract IoBuffer putFloat(float value); - - - /** - * @see ByteBuffer#getFloat(int) - */ - public abstract float getFloat(int index); - - - /** - * @see ByteBuffer#putFloat(int, float) - */ - public abstract IoBuffer putFloat(int index, float value); - - - /** - * @see ByteBuffer#asFloatBuffer() - */ - public abstract FloatBuffer asFloatBuffer(); - - - /** - * @see ByteBuffer#getDouble() - */ - public abstract double getDouble(); - - - /** - * @see ByteBuffer#putDouble(double) - */ - public abstract IoBuffer putDouble(double value); - - - /** - * @see ByteBuffer#getDouble(int) - */ - public abstract double getDouble(int index); - - - /** - * @see ByteBuffer#putDouble(int, double) - */ - public abstract IoBuffer putDouble(int index, double value); - - - /** - * @see ByteBuffer#asDoubleBuffer() - */ - public abstract DoubleBuffer asDoubleBuffer(); - - - /** - * Returns an {@link InputStream} that reads the data from this buffer. - * {@link InputStream#read()} returns -1 if the buffer position - * reaches to the limit. - */ - public abstract InputStream asInputStream(); - - - /** - * Returns an {@link OutputStream} that appends the data into this buffer. - * Please note that the {@link OutputStream#write(int)} will throw a - * {@link BufferOverflowException} instead of an {@link IOException} in case - * of buffer overflow. Please set autoExpand property by calling - * {@link #setAutoExpand(boolean)} to prevent the unexpected runtime - * exception. - */ - public abstract OutputStream asOutputStream(); - - - /** - * Returns hexdump of this buffer. The data and pointer are not changed as a - * result of this method call. - * - * @return hexidecimal representation of this buffer - */ - public abstract String getHexDump(); - - - /** - * Return hexdump of this buffer with limited length. - * - * @param lengthLimit - * The maximum number of bytes to dump from the current buffer - * position. - * @return hexidecimal representation of this buffer - */ - public abstract String getHexDump(int lengthLimit); - - - // ////////////////////////////// - // String getters and putters // - // ////////////////////////////// - - /** - * Reads a NUL-terminated string from this buffer using the - * specified decoder and returns it. This method reads until - * the limit of this buffer if no NUL is found. - */ - public abstract String getString(CharsetDecoder decoder) throws CharacterCodingException; - - - /** - * Reads a NUL-terminated string from this buffer using the - * specified decoder and returns it. - * - * @param fieldSize - * the maximum number of bytes to read - */ - public abstract String getString(int fieldSize, CharsetDecoder decoder) throws CharacterCodingException; - - - /** - * Writes the content of in into this buffer using the - * specified encoder. This method doesn't terminate string with - * NUL. You have to do it by yourself. - * - * @throws BufferOverflowException - * if the specified string doesn't fit - */ - public abstract IoBuffer putString(CharSequence val, CharsetEncoder encoder) throws CharacterCodingException; - - - /** - * Writes the content of in into this buffer as a - * NUL-terminated string using the specified - * encoder. - *

- * If the charset name of the encoder is UTF-16, you cannot specify odd - * fieldSize, and this method will append two NULs - * as a terminator. - *

- * Please note that this method doesn't terminate with NUL if - * the input string is longer than fieldSize. - * - * @param fieldSize - * the maximum number of bytes to write - */ - public abstract IoBuffer putString(CharSequence val, int fieldSize, CharsetEncoder encoder) - throws CharacterCodingException; - - - /** - * Reads a string which has a 16-bit length field before the actual encoded - * string, using the specified decoder and returns it. This - * method is a shortcut for getPrefixedString(2, decoder). - */ - public abstract String getPrefixedString(CharsetDecoder decoder) throws CharacterCodingException; - - - /** - * Reads a string which has a length field before the actual encoded string, - * using the specified decoder and returns it. - * - * @param prefixLength - * the length of the length field (1, 2, or 4) - */ - public abstract String getPrefixedString(int prefixLength, CharsetDecoder decoder) throws CharacterCodingException; - - - /** - * Writes the content of in into this buffer as a string which - * has a 16-bit length field before the actual encoded string, using the - * specified encoder. This method is a shortcut for - * putPrefixedString(in, 2, 0, encoder). - * - * @throws BufferOverflowException - * if the specified string doesn't fit - */ - public abstract IoBuffer putPrefixedString(CharSequence in, CharsetEncoder encoder) throws CharacterCodingException; - - - /** - * Writes the content of in into this buffer as a string which - * has a 16-bit length field before the actual encoded string, using the - * specified encoder. This method is a shortcut for - * putPrefixedString(in, prefixLength, 0, encoder). - * - * @param prefixLength - * the length of the length field (1, 2, or 4) - * - * @throws BufferOverflowException - * if the specified string doesn't fit - */ - public abstract IoBuffer putPrefixedString(CharSequence in, int prefixLength, CharsetEncoder encoder) - throws CharacterCodingException; - - - /** - * Writes the content of in into this buffer as a string which - * has a 16-bit length field before the actual encoded string, using the - * specified encoder. This method is a shortcut for - * putPrefixedString(in, prefixLength, padding, ( byte ) 0, encoder) - * . - * - * @param prefixLength - * the length of the length field (1, 2, or 4) - * @param padding - * the number of padded NULs (1 (or 0), 2, or 4) - * - * @throws BufferOverflowException - * if the specified string doesn't fit - */ - public abstract IoBuffer putPrefixedString(CharSequence in, int prefixLength, int padding, CharsetEncoder encoder) - throws CharacterCodingException; - - - /** - * Writes the content of in into this buffer as a string which - * has a 16-bit length field before the actual encoded string, using the - * specified encoder. - * - * @param prefixLength - * the length of the length field (1, 2, or 4) - * @param padding - * the number of padded bytes (1 (or 0), 2, or 4) - * @param padValue - * the value of padded bytes - * - * @throws BufferOverflowException - * if the specified string doesn't fit - */ - public abstract IoBuffer putPrefixedString(CharSequence val, int prefixLength, int padding, byte padValue, - CharsetEncoder encoder) throws CharacterCodingException; - - - /** - * Reads a Java object from the buffer using the context {@link ClassLoader} - * of the current thread. - */ - public abstract Object getObject() throws ClassNotFoundException; - - - /** - * Reads a Java object from the buffer using the specified - * classLoader. - */ - public abstract Object getObject(final ClassLoader classLoader) throws ClassNotFoundException; - - - /** - * Writes the specified Java object to the buffer. - */ - public abstract IoBuffer putObject(Object o); - - - /** - * Returns true if this buffer contains a data which has a data - * length as a prefix and the buffer has remaining data as enough as - * specified in the data length field. This method is identical with - * prefixedDataAvailable( prefixLength, Integer.MAX_VALUE ). Please - * not that using this method can allow DoS (Denial of Service) attack in - * case the remote peer sends too big data length value. It is recommended - * to use {@link #prefixedDataAvailable(int, int)} instead. - * - * @param prefixLength - * the length of the prefix field (1, 2, or 4) - * - * @throws IllegalArgumentException - * if prefixLength is wrong - * @throws BufferDataException - * if data length is negative - */ - public abstract boolean prefixedDataAvailable(int prefixLength); - - - /** - * Returns true if this buffer contains a data which has a data - * length as a prefix and the buffer has remaining data as enough as - * specified in the data length field. - * - * @param prefixLength - * the length of the prefix field (1, 2, or 4) - * @param maxDataLength - * the allowed maximum of the read data length - * - * @throws IllegalArgumentException - * if prefixLength is wrong - * @throws BufferDataException - * if data length is negative or greater then - * maxDataLength - */ - public abstract boolean prefixedDataAvailable(int prefixLength, int maxDataLength); - - - // /////////////////// - // IndexOf methods // - // /////////////////// - - /** - * Returns the first occurence position of the specified byte from the - * current position to the current limit. - * - * @return -1 if the specified byte is not found - */ - public abstract int indexOf(byte b); - - - // //////////////////////// - // Skip or fill methods // - // //////////////////////// - - /** - * Forwards the position of this buffer as the specified size - * bytes. - */ - public abstract IoBuffer skip(int size); - - - /** - * Fills this buffer with the specified value. This method moves buffer - * position forward. - */ - public abstract IoBuffer fill(byte value, int size); - - - /** - * Fills this buffer with the specified value. This method does not change - * buffer position. - */ - public abstract IoBuffer fillAndReset(byte value, int size); - - - /** - * Fills this buffer with NUL (0x00). This method moves buffer - * position forward. - */ - public abstract IoBuffer fill(int size); - - - /** - * Fills this buffer with NUL (0x00). This method does not - * change buffer position. - */ - public abstract IoBuffer fillAndReset(int size); - - - // //////////////////////// - // Enum methods // - // //////////////////////// - - /** - * Reads a byte from the buffer and returns the correlating enum constant - * defined by the specified enum type. - * - * @param - * The enum type to return - * @param enumClass - * The enum's class object - */ - public abstract > E getEnum(Class enumClass); - - - /** - * Reads a byte from the buffer and returns the correlating enum constant - * defined by the specified enum type. - * - * @param - * The enum type to return - * @param index - * the index from which the byte will be read - * @param enumClass - * The enum's class object - */ - public abstract > E getEnum(int index, Class enumClass); - - - /** - * Reads a short from the buffer and returns the correlating enum constant - * defined by the specified enum type. - * - * @param - * The enum type to return - * @param enumClass - * The enum's class object - */ - public abstract > E getEnumShort(Class enumClass); - - - /** - * Reads a short from the buffer and returns the correlating enum constant - * defined by the specified enum type. - * - * @param - * The enum type to return - * @param index - * the index from which the bytes will be read - * @param enumClass - * The enum's class object - */ - public abstract > E getEnumShort(int index, Class enumClass); - - - /** - * Reads an int from the buffer and returns the correlating enum constant - * defined by the specified enum type. - * - * @param - * The enum type to return - * @param enumClass - * The enum's class object - */ - public abstract > E getEnumInt(Class enumClass); - - - /** - * Reads an int from the buffer and returns the correlating enum constant - * defined by the specified enum type. - * - * @param - * The enum type to return - * @param index - * the index from which the bytes will be read - * @param enumClass - * The enum's class object - */ - public abstract > E getEnumInt(int index, Class enumClass); - - - /** - * Writes an enum's ordinal value to the buffer as a byte. - * - * @param e - * The enum to write to the buffer - */ - public abstract IoBuffer putEnum(Enum e); - - - /** - * Writes an enum's ordinal value to the buffer as a byte. - * - * @param index - * The index at which the byte will be written - * @param e - * The enum to write to the buffer - */ - public abstract IoBuffer putEnum(int index, Enum e); - - - /** - * Writes an enum's ordinal value to the buffer as a short. - * - * @param e - * The enum to write to the buffer - */ - public abstract IoBuffer putEnumShort(Enum e); - - - /** - * Writes an enum's ordinal value to the buffer as a short. - * - * @param index - * The index at which the bytes will be written - * @param e - * The enum to write to the buffer - */ - public abstract IoBuffer putEnumShort(int index, Enum e); - - - /** - * Writes an enum's ordinal value to the buffer as an integer. - * - * @param e - * The enum to write to the buffer - */ - public abstract IoBuffer putEnumInt(Enum e); - - - /** - * Writes an enum's ordinal value to the buffer as an integer. - * - * @param index - * The index at which the bytes will be written - * @param e - * The enum to write to the buffer - */ - public abstract IoBuffer putEnumInt(int index, Enum e); - - - // //////////////////////// - // EnumSet methods // - // //////////////////////// - - /** - * Reads a byte sized bit vector and converts it to an {@link EnumSet}. - * - *

- * Each bit is mapped to a value in the specified enum. The least - * significant bit maps to the first entry in the specified enum and each - * subsequent bit maps to each subsequent bit as mapped to the subsequent - * enum value. - *

- * - * @param - * the enum type - * @param enumClass - * the enum class used to create the EnumSet - * @return the EnumSet representation of the bit vector - */ - public abstract > EnumSet getEnumSet(Class enumClass); - - - /** - * Reads a byte sized bit vector and converts it to an {@link EnumSet}. - * - * @see #getEnumSet(Class) - * @param - * the enum type - * @param index - * the index from which the byte will be read - * @param enumClass - * the enum class used to create the EnumSet - * @return the EnumSet representation of the bit vector - */ - public abstract > EnumSet getEnumSet(int index, Class enumClass); - - - /** - * Reads a short sized bit vector and converts it to an {@link EnumSet}. - * - * @see #getEnumSet(Class) - * @param - * the enum type - * @param enumClass - * the enum class used to create the EnumSet - * @return the EnumSet representation of the bit vector - */ - public abstract > EnumSet getEnumSetShort(Class enumClass); - - - /** - * Reads a short sized bit vector and converts it to an {@link EnumSet}. - * - * @see #getEnumSet(Class) - * @param - * the enum type - * @param index - * the index from which the bytes will be read - * @param enumClass - * the enum class used to create the EnumSet - * @return the EnumSet representation of the bit vector - */ - public abstract > EnumSet getEnumSetShort(int index, Class enumClass); - - - /** - * Reads an int sized bit vector and converts it to an {@link EnumSet}. - * - * @see #getEnumSet(Class) - * @param - * the enum type - * @param enumClass - * the enum class used to create the EnumSet - * @return the EnumSet representation of the bit vector - */ - public abstract > EnumSet getEnumSetInt(Class enumClass); - - - /** - * Reads an int sized bit vector and converts it to an {@link EnumSet}. - * - * @see #getEnumSet(Class) - * @param - * the enum type - * @param index - * the index from which the bytes will be read - * @param enumClass - * the enum class used to create the EnumSet - * @return the EnumSet representation of the bit vector - */ - public abstract > EnumSet getEnumSetInt(int index, Class enumClass); - - - /** - * Reads a long sized bit vector and converts it to an {@link EnumSet}. - * - * @see #getEnumSet(Class) - * @param - * the enum type - * @param enumClass - * the enum class used to create the EnumSet - * @return the EnumSet representation of the bit vector - */ - public abstract > EnumSet getEnumSetLong(Class enumClass); - - - /** - * Reads a long sized bit vector and converts it to an {@link EnumSet}. - * - * @see #getEnumSet(Class) - * @param - * the enum type - * @param index - * the index from which the bytes will be read - * @param enumClass - * the enum class used to create the EnumSet - * @return the EnumSet representation of the bit vector - */ - public abstract > EnumSet getEnumSetLong(int index, Class enumClass); - - - /** - * Writes the specified {@link Set} to the buffer as a byte sized bit - * vector. - * - * @param - * the enum type of the Set - * @param set - * the enum set to write to the buffer - */ - public abstract > IoBuffer putEnumSet(Set set); - - - /** - * Writes the specified {@link Set} to the buffer as a byte sized bit - * vector. - * - * @param - * the enum type of the Set - * @param index - * the index at which the byte will be written - * @param set - * the enum set to write to the buffer - */ - public abstract > IoBuffer putEnumSet(int index, Set set); - - - /** - * Writes the specified {@link Set} to the buffer as a short sized bit - * vector. - * - * @param - * the enum type of the Set - * @param set - * the enum set to write to the buffer - */ - public abstract > IoBuffer putEnumSetShort(Set set); - - - /** - * Writes the specified {@link Set} to the buffer as a short sized bit - * vector. - * - * @param - * the enum type of the Set - * @param index - * the index at which the bytes will be written - * @param set - * the enum set to write to the buffer - */ - public abstract > IoBuffer putEnumSetShort(int index, Set set); - - - /** - * Writes the specified {@link Set} to the buffer as an int sized bit - * vector. - * - * @param - * the enum type of the Set - * @param set - * the enum set to write to the buffer - */ - public abstract > IoBuffer putEnumSetInt(Set set); - - - /** - * Writes the specified {@link Set} to the buffer as an int sized bit - * vector. - * - * @param - * the enum type of the Set - * @param index - * the index at which the bytes will be written - * @param set - * the enum set to write to the buffer - */ - public abstract > IoBuffer putEnumSetInt(int index, Set set); - - - /** - * Writes the specified {@link Set} to the buffer as a long sized bit - * vector. - * - * @param - * the enum type of the Set - * @param set - * the enum set to write to the buffer - */ - public abstract > IoBuffer putEnumSetLong(Set set); - - - /** - * Writes the specified {@link Set} to the buffer as a long sized bit - * vector. - * - * @param - * the enum type of the Set - * @param index - * the index at which the bytes will be written - * @param set - * the enum set to write to the buffer - */ - public abstract > IoBuffer putEnumSetLong(int index, Set set); + /** The allocator used to create new buffers */ + private static IoBufferAllocator allocator = new SimpleBufferAllocator(); + + /** A flag indicating which type of buffer we are using : heap or direct */ + private static boolean useDirectBuffer = false; + + /** + * Returns the allocator used by existing and new buffers + */ + public static IoBufferAllocator getAllocator() { + return allocator; + } + + /** + * Sets the allocator used by existing and new buffers + */ + public static void setAllocator(IoBufferAllocator newAllocator) { + if (newAllocator == null) { + throw new NullPointerException("allocator"); + } + + IoBufferAllocator oldAllocator = allocator; + + allocator = newAllocator; + + if (null != oldAllocator) { + oldAllocator.dispose(); + } + } + + /** + * Returns true if and only if a direct buffer is allocated by + * default when the type of the new buffer is not specified. The default + * value is false. + */ + public static boolean isUseDirectBuffer() { + return useDirectBuffer; + } + + /** + * Sets if a direct buffer should be allocated by default when the type of + * the new buffer is not specified. The default value is false. + */ + public static void setUseDirectBuffer(boolean useDirectBuffer) { + IoBuffer.useDirectBuffer = useDirectBuffer; + } + + /** + * Returns the direct or heap buffer which is capable to store the specified + * amount of bytes. + * + * @param capacity + * the capacity of the buffer + * + * @see #setUseDirectBuffer(boolean) + */ + public static IoBuffer allocate(int capacity) { + return allocate(capacity, useDirectBuffer); + } + + /** + * Returns the buffer which is capable of the specified size. + * + * @param capacity + * the capacity of the buffer + * @param direct + * true to get a direct buffer, false to get a + * heap buffer. + */ + public static IoBuffer allocate(int capacity, boolean direct) { + if (capacity < 0) { + throw new IllegalArgumentException("capacity: " + capacity); + } + + return allocator.allocate(capacity, direct); + } + + /** + * Wraps the specified NIO {@link ByteBuffer} into MINA buffer. + */ + public static IoBuffer wrap(ByteBuffer nioBuffer) { + return allocator.wrap(nioBuffer); + } + + /** + * Wraps the specified byte array into MINA heap buffer. + */ + public static IoBuffer wrap(byte[] byteArray) { + return wrap(ByteBuffer.wrap(byteArray)); + } + + /** + * Wraps the specified byte array into MINA heap buffer. + */ + public static IoBuffer wrap(byte[] byteArray, int offset, int length) { + return wrap(ByteBuffer.wrap(byteArray, offset, length)); + } + + /** + * Normalizes the specified capacity of the buffer to power of 2, which is + * often helpful for optimal memory usage and performance. If it is greater + * than or equal to {@link Integer#MAX_VALUE}, it returns + * {@link Integer#MAX_VALUE}. If it is zero, it returns zero. + */ + protected static int normalizeCapacity(int requestedCapacity) { + switch (requestedCapacity) { + case 0 : + case 1 << 0 : + case 1 << 1 : + case 1 << 2 : + case 1 << 3 : + case 1 << 4 : + case 1 << 5 : + case 1 << 6 : + case 1 << 7 : + case 1 << 8 : + case 1 << 9 : + case 1 << 10 : + case 1 << 11 : + case 1 << 12 : + case 1 << 13 : + case 1 << 14 : + case 1 << 15 : + case 1 << 16 : + case 1 << 17 : + case 1 << 18 : + case 1 << 19 : + case 1 << 21 : + case 1 << 22 : + case 1 << 23 : + case 1 << 24 : + case 1 << 25 : + case 1 << 26 : + case 1 << 27 : + case 1 << 28 : + case 1 << 29 : + case 1 << 30 : + case Integer.MAX_VALUE : + return requestedCapacity; + } + + int newCapacity = 1; + while (newCapacity < requestedCapacity) { + newCapacity <<= 1; + if (newCapacity < 0) { + return Integer.MAX_VALUE; + } + } + return newCapacity; + } + + /** + * Creates a new instance. This is an empty constructor. + */ + protected IoBuffer() { + } + + /** + * Declares this buffer and all its derived buffers are not used anymore so + * that it can be reused by some {@link IoBufferAllocator} implementations. + * It is not mandatory to call this method, but you might want to invoke + * this method for maximum performance. + */ + public abstract void free(); + + /** + * Returns the underlying NIO buffer instance. + */ + public abstract ByteBuffer buf(); + + /** + * @see ByteBuffer#isDirect() + */ + public abstract boolean isDirect(); + + /** + * returns true if and only if this buffer is derived from other + * buffer via {@link #duplicate()}, {@link #slice()} or + * {@link #asReadOnlyBuffer()}. + */ + public abstract boolean isDerived(); + + /** + * @see ByteBuffer#isReadOnly() + */ + public abstract boolean isReadOnly(); + + /** + * Returns the minimum capacity of this buffer which is used to determine + * the new capacity of the buffer shrunk by {@link #compact()} and + * {@link #shrink()} operation. The default value is the initial capacity of + * the buffer. + */ + public abstract int minimumCapacity(); + + /** + * Sets the minimum capacity of this buffer which is used to determine the + * new capacity of the buffer shrunk by {@link #compact()} and + * {@link #shrink()} operation. The default value is the initial capacity of + * the buffer. + */ + public abstract IoBuffer minimumCapacity(int minimumCapacity); + + /** + * @see ByteBuffer#capacity() + */ + public abstract int capacity(); + + /** + * Increases the capacity of this buffer. If the new capacity is less than + * or equal to the current capacity, this method returns silently. If the + * new capacity is greater than the current capacity, the buffer is + * reallocated while retaining the position, limit, mark and the content of + * the buffer. + */ + public abstract IoBuffer capacity(int newCapacity); + + /** + * Returns true if and only if autoExpand is turned on. + */ + public abstract boolean isAutoExpand(); + + /** + * Turns on or off autoExpand. + */ + public abstract IoBuffer setAutoExpand(boolean autoExpand); + + /** + * Returns true if and only if autoShrink is turned on. + */ + public abstract boolean isAutoShrink(); + + /** + * Turns on or off autoShrink. + */ + public abstract IoBuffer setAutoShrink(boolean autoShrink); + + /** + * Changes the capacity and limit of this buffer so this buffer get the + * specified expectedRemaining room from the current position. This + * method works even if you didn't set autoExpand to true. + */ + public abstract IoBuffer expand(int expectedRemaining); + + /** + * Changes the capacity and limit of this buffer so this buffer get the + * specified expectedRemaining room from the specified + * position. This method works even if you didn't set + * autoExpand to true. + */ + public abstract IoBuffer expand(int position, int expectedRemaining); + + /** + * Changes the capacity of this buffer so this buffer occupies as less + * memory as possible while retaining the position, limit and the buffer + * content between the position and limit. The capacity of the buffer never + * becomes less than {@link #minimumCapacity()}. The mark is discarded once + * the capacity changes. + */ + public abstract IoBuffer shrink(); + + /** + * @see java.nio.Buffer#position() + */ + public abstract int position(); + + /** + * @see java.nio.Buffer#position(int) + */ + public abstract IoBuffer position(int newPosition); + + /** + * @see java.nio.Buffer#limit() + */ + public abstract int limit(); + + /** + * @see java.nio.Buffer#limit(int) + */ + public abstract IoBuffer limit(int newLimit); + + /** + * @see java.nio.Buffer#mark() + */ + public abstract IoBuffer mark(); + + /** + * Returns the position of the current mark. This method returns -1 + * if no mark is set. + */ + public abstract int markValue(); + + /** + * @see java.nio.Buffer#reset() + */ + public abstract IoBuffer reset(); + + /** + * @see java.nio.Buffer#clear() + */ + public abstract IoBuffer clear(); + + /** + * Clears this buffer and fills its content with NUL. The position + * is set to zero, the limit is set to the capacity, and the mark is + * discarded. + */ + public abstract IoBuffer sweep(); + + /** + * double Clears this buffer and fills its content with value. The + * position is set to zero, the limit is set to the capacity, and the mark + * is discarded. + */ + public abstract IoBuffer sweep(byte value); + + /** + * @see java.nio.Buffer#flip() + */ + public abstract IoBuffer flip(); + + /** + * @see java.nio.Buffer#rewind() + */ + public abstract IoBuffer rewind(); + + /** + * @see java.nio.Buffer#remaining() + */ + public abstract int remaining(); + + /** + * @see java.nio.Buffer#hasRemaining() + */ + public abstract boolean hasRemaining(); + + /** + * @see ByteBuffer#duplicate() + */ + public abstract IoBuffer duplicate(); + + /** + * @see ByteBuffer#slice() + */ + public abstract IoBuffer slice(); + + /** + * @see ByteBuffer#asReadOnlyBuffer() + */ + public abstract IoBuffer asReadOnlyBuffer(); + + /** + * @see ByteBuffer#hasArray() + */ + public abstract boolean hasArray(); + + /** + * @see ByteBuffer#array() + */ + public abstract byte[] array(); + + /** + * @see ByteBuffer#arrayOffset() + */ + public abstract int arrayOffset(); + + /** + * @see ByteBuffer#get() + */ + public abstract byte get(); + + /** + * Reads one unsigned byte as a short integer. + */ + public abstract short getUnsigned(); + + /** + * @see ByteBuffer#put(byte) + */ + public abstract IoBuffer put(byte b); + + /** + * @see ByteBuffer#get(int) + */ + public abstract byte get(int index); + + /** + * Reads one byte as an unsigned short integer. + */ + public abstract short getUnsigned(int index); + + /** + * @see ByteBuffer#put(int, byte) + */ + public abstract IoBuffer put(int index, byte b); + + /** + * @see ByteBuffer#get(byte[], int, int) + */ + public abstract IoBuffer get(byte[] dst, int offset, int length); + + /** + * @see ByteBuffer#get(byte[]) + */ + public abstract IoBuffer get(byte[] dst); + + /** + * TODO document me. + */ + public abstract IoBuffer getSlice(int index, int length); + + /** + * TODO document me. + */ + public abstract IoBuffer getSlice(int length); + + /** + * Writes the content of the specified src into this buffer. + */ + public abstract IoBuffer put(ByteBuffer src); + + /** + * Writes the content of the specified src into this buffer. + */ + public abstract IoBuffer put(IoBuffer src); + + /** + * @see ByteBuffer#put(byte[], int, int) + */ + public abstract IoBuffer put(byte[] src, int offset, int length); + + /** + * @see ByteBuffer#put(byte[]) + */ + public abstract IoBuffer put(byte[] src); + + /** + * @see ByteBuffer#compact() + */ + public abstract IoBuffer compact(); + + /** + * @see ByteBuffer#order() + */ + public abstract ByteOrder order(); + + /** + * @see ByteBuffer#order(ByteOrder) + */ + public abstract IoBuffer order(ByteOrder bo); + + /** + * @see ByteBuffer#getChar() + */ + public abstract char getChar(); + + /** + * @see ByteBuffer#putChar(char) + */ + public abstract IoBuffer putChar(char value); + + /** + * @see ByteBuffer#getChar(int) + */ + public abstract char getChar(int index); + + /** + * @see ByteBuffer#putChar(int, char) + */ + public abstract IoBuffer putChar(int index, char value); + + /** + * @see ByteBuffer#asCharBuffer() + */ + public abstract CharBuffer asCharBuffer(); + + /** + * @see ByteBuffer#getShort() + */ + public abstract short getShort(); + + /** + * Reads two bytes unsigned integer. + */ + public abstract int getUnsignedShort(); + + /** + * @see ByteBuffer#putShort(short) + */ + public abstract IoBuffer putShort(short value); + + /** + * @see ByteBuffer#getShort() + */ + public abstract short getShort(int index); + + /** + * Reads two bytes unsigned integer. + */ + public abstract int getUnsignedShort(int index); + + /** + * @see ByteBuffer#putShort(int, short) + */ + public abstract IoBuffer putShort(int index, short value); + + /** + * @see ByteBuffer#asShortBuffer() + */ + public abstract ShortBuffer asShortBuffer(); + + /** + * @see ByteBuffer#getInt() + */ + public abstract int getInt(); + + /** + * Reads four bytes unsigned integer. + */ + public abstract long getUnsignedInt(); + + /** + * Relative get method for reading a medium int value. + * + *

+ * Reads the next three bytes at this buffer's current position, composing + * them into an int value according to the current byte order, and then + * increments the position by three. + *

+ * + * @return The medium int value at the buffer's current position + */ + public abstract int getMediumInt(); + + /** + * Relative get method for reading an unsigned medium int value. + * + *

+ * Reads the next three bytes at this buffer's current position, composing + * them into an int value according to the current byte order, and then + * increments the position by three. + *

+ * + * @return The unsigned medium int value at the buffer's current position + */ + public abstract int getUnsignedMediumInt(); + + /** + * Absolute get method for reading a medium int value. + * + *

+ * Reads the next three bytes at this buffer's current position, composing + * them into an int value according to the current byte order. + *

+ * + * @param index + * The index from which the medium int will be read + * @return The medium int value at the given index + * + * @throws IndexOutOfBoundsException + * If index is negative or not smaller than the + * buffer's limit + */ + public abstract int getMediumInt(int index); + + /** + * Absolute get method for reading an unsigned medium int value. + * + *

+ * Reads the next three bytes at this buffer's current position, composing + * them into an int value according to the current byte order. + *

+ * + * @param index + * The index from which the unsigned medium int will be read + * @return The unsigned medium int value at the given index + * + * @throws IndexOutOfBoundsException + * If index is negative or not smaller than the + * buffer's limit + */ + public abstract int getUnsignedMediumInt(int index); + + /** + * Relative put method for writing a medium int value. + * + *

+ * Writes three bytes containing the given int value, in the current byte + * order, into this buffer at the current position, and then increments the + * position by three. + *

+ * + * @param value + * The medium int value to be written + * + * @return This buffer + * + * @throws BufferOverflowException + * If there are fewer than three bytes remaining in this buffer + * + * @throws ReadOnlyBufferException + * If this buffer is read-only + */ + public abstract IoBuffer putMediumInt(int value); + + /** + * Absolute put method for writing a medium int value. + * + *

+ * Writes three bytes containing the given int value, in the current byte + * order, into this buffer at the given index. + *

+ * + * @param index + * The index at which the bytes will be written + * + * @param value + * The medium int value to be written + * + * @return This buffer + * + * @throws IndexOutOfBoundsException + * If index is negative or not smaller than the + * buffer's limit, minus three + * + * @throws ReadOnlyBufferException + * If this buffer is read-only + */ + public abstract IoBuffer putMediumInt(int index, int value); + + /** + * @see ByteBuffer#putInt(int) + */ + public abstract IoBuffer putInt(int value); + + /** + * @see ByteBuffer#getInt(int) + */ + public abstract int getInt(int index); + + /** + * Reads four bytes unsigned integer. + */ + public abstract long getUnsignedInt(int index); + + /** + * @see ByteBuffer#putInt(int, int) + */ + public abstract IoBuffer putInt(int index, int value); + + /** + * @see ByteBuffer#asIntBuffer() + */ + public abstract IntBuffer asIntBuffer(); + + /** + * @see ByteBuffer#getLong() + */ + public abstract long getLong(); + + /** + * @see ByteBuffer#putLong(int, long) + */ + public abstract IoBuffer putLong(long value); + + /** + * @see ByteBuffer#getLong(int) + */ + public abstract long getLong(int index); + + /** + * @see ByteBuffer#putLong(int, long) + */ + public abstract IoBuffer putLong(int index, long value); + + /** + * @see ByteBuffer#asLongBuffer() + */ + public abstract LongBuffer asLongBuffer(); + + /** + * @see ByteBuffer#getFloat() + */ + public abstract float getFloat(); + + /** + * @see ByteBuffer#putFloat(float) + */ + public abstract IoBuffer putFloat(float value); + + /** + * @see ByteBuffer#getFloat(int) + */ + public abstract float getFloat(int index); + + /** + * @see ByteBuffer#putFloat(int, float) + */ + public abstract IoBuffer putFloat(int index, float value); + + /** + * @see ByteBuffer#asFloatBuffer() + */ + public abstract FloatBuffer asFloatBuffer(); + + /** + * @see ByteBuffer#getDouble() + */ + public abstract double getDouble(); + + /** + * @see ByteBuffer#putDouble(double) + */ + public abstract IoBuffer putDouble(double value); + + /** + * @see ByteBuffer#getDouble(int) + */ + public abstract double getDouble(int index); + + /** + * @see ByteBuffer#putDouble(int, double) + */ + public abstract IoBuffer putDouble(int index, double value); + + /** + * @see ByteBuffer#asDoubleBuffer() + */ + public abstract DoubleBuffer asDoubleBuffer(); + + /** + * Returns an {@link InputStream} that reads the data from this buffer. + * {@link InputStream#read()} returns -1 if the buffer position + * reaches to the limit. + */ + public abstract InputStream asInputStream(); + + /** + * Returns an {@link OutputStream} that appends the data into this buffer. + * Please note that the {@link OutputStream#write(int)} will throw a + * {@link BufferOverflowException} instead of an {@link IOException} in case + * of buffer overflow. Please set autoExpand property by calling + * {@link #setAutoExpand(boolean)} to prevent the unexpected runtime + * exception. + */ + public abstract OutputStream asOutputStream(); + + /** + * Returns hexdump of this buffer. The data and pointer are not changed as a + * result of this method call. + * + * @return hexidecimal representation of this buffer + */ + public abstract String getHexDump(); + + /** + * Return hexdump of this buffer with limited length. + * + * @param lengthLimit + * The maximum number of bytes to dump from the current buffer + * position. + * @return hexidecimal representation of this buffer + */ + public abstract String getHexDump(int lengthLimit); + + // ////////////////////////////// + // String getters and putters // + // ////////////////////////////// + + /** + * Reads a NUL-terminated string from this buffer using the + * specified decoder and returns it. This method reads until + * the limit of this buffer if no NUL is found. + */ + public abstract String getString(CharsetDecoder decoder) + throws CharacterCodingException; + + /** + * Reads a NUL-terminated string from this buffer using the + * specified decoder and returns it. + * + * @param fieldSize + * the maximum number of bytes to read + */ + public abstract String getString(int fieldSize, CharsetDecoder decoder) + throws CharacterCodingException; + + /** + * Writes the content of in into this buffer using the + * specified encoder. This method doesn't terminate string with + * NUL. You have to do it by yourself. + * + * @throws BufferOverflowException + * if the specified string doesn't fit + */ + public abstract IoBuffer putString(CharSequence val, CharsetEncoder encoder) + throws CharacterCodingException; + + /** + * Writes the content of in into this buffer as a + * NUL-terminated string using the specified + * encoder. + *

+ * If the charset name of the encoder is UTF-16, you cannot specify odd + * fieldSize, and this method will append two NULs + * as a terminator. + *

+ * Please note that this method doesn't terminate with NUL if + * the input string is longer than fieldSize. + * + * @param fieldSize + * the maximum number of bytes to write + */ + public abstract IoBuffer putString(CharSequence val, int fieldSize, + CharsetEncoder encoder) throws CharacterCodingException; + + /** + * Reads a string which has a 16-bit length field before the actual encoded + * string, using the specified decoder and returns it. This + * method is a shortcut for getPrefixedString(2, decoder). + */ + public abstract String getPrefixedString(CharsetDecoder decoder) + throws CharacterCodingException; + + /** + * Reads a string which has a length field before the actual encoded string, + * using the specified decoder and returns it. + * + * @param prefixLength + * the length of the length field (1, 2, or 4) + */ + public abstract String getPrefixedString(int prefixLength, + CharsetDecoder decoder) throws CharacterCodingException; + + /** + * Writes the content of in into this buffer as a string which + * has a 16-bit length field before the actual encoded string, using the + * specified encoder. This method is a shortcut for + * putPrefixedString(in, 2, 0, encoder). + * + * @throws BufferOverflowException + * if the specified string doesn't fit + */ + public abstract IoBuffer putPrefixedString(CharSequence in, + CharsetEncoder encoder) throws CharacterCodingException; + + /** + * Writes the content of in into this buffer as a string which + * has a 16-bit length field before the actual encoded string, using the + * specified encoder. This method is a shortcut for + * putPrefixedString(in, prefixLength, 0, encoder). + * + * @param prefixLength + * the length of the length field (1, 2, or 4) + * + * @throws BufferOverflowException + * if the specified string doesn't fit + */ + public abstract IoBuffer putPrefixedString(CharSequence in, + int prefixLength, CharsetEncoder encoder) + throws CharacterCodingException; + + /** + * Writes the content of in into this buffer as a string which + * has a 16-bit length field before the actual encoded string, using the + * specified encoder. This method is a shortcut for + * putPrefixedString(in, prefixLength, padding, ( byte ) 0, encoder) + * . + * + * @param prefixLength + * the length of the length field (1, 2, or 4) + * @param padding + * the number of padded NULs (1 (or 0), 2, or 4) + * + * @throws BufferOverflowException + * if the specified string doesn't fit + */ + public abstract IoBuffer putPrefixedString(CharSequence in, + int prefixLength, int padding, CharsetEncoder encoder) + throws CharacterCodingException; + + /** + * Writes the content of in into this buffer as a string which + * has a 16-bit length field before the actual encoded string, using the + * specified encoder. + * + * @param prefixLength + * the length of the length field (1, 2, or 4) + * @param padding + * the number of padded bytes (1 (or 0), 2, or 4) + * @param padValue + * the value of padded bytes + * + * @throws BufferOverflowException + * if the specified string doesn't fit + */ + public abstract IoBuffer putPrefixedString(CharSequence val, + int prefixLength, int padding, byte padValue, + CharsetEncoder encoder) throws CharacterCodingException; + + /** + * Reads a Java object from the buffer using the context {@link ClassLoader} + * of the current thread. + */ + public abstract Object getObject() throws ClassNotFoundException; + + /** + * Reads a Java object from the buffer using the specified + * classLoader. + */ + public abstract Object getObject(final ClassLoader classLoader) + throws ClassNotFoundException; + + /** + * Writes the specified Java object to the buffer. + */ + public abstract IoBuffer putObject(Object o); + + /** + * Returns true if this buffer contains a data which has a data + * length as a prefix and the buffer has remaining data as enough as + * specified in the data length field. This method is identical with + * prefixedDataAvailable( prefixLength, Integer.MAX_VALUE ). Please + * not that using this method can allow DoS (Denial of Service) attack in + * case the remote peer sends too big data length value. It is recommended + * to use {@link #prefixedDataAvailable(int, int)} instead. + * + * @param prefixLength + * the length of the prefix field (1, 2, or 4) + * + * @throws IllegalArgumentException + * if prefixLength is wrong + * @throws BufferDataException + * if data length is negative + */ + public abstract boolean prefixedDataAvailable(int prefixLength); + + /** + * Returns true if this buffer contains a data which has a data + * length as a prefix and the buffer has remaining data as enough as + * specified in the data length field. + * + * @param prefixLength + * the length of the prefix field (1, 2, or 4) + * @param maxDataLength + * the allowed maximum of the read data length + * + * @throws IllegalArgumentException + * if prefixLength is wrong + * @throws BufferDataException + * if data length is negative or greater then + * maxDataLength + */ + public abstract boolean prefixedDataAvailable(int prefixLength, + int maxDataLength); + + // /////////////////// + // IndexOf methods // + // /////////////////// + + /** + * Returns the first occurence position of the specified byte from the + * current position to the current limit. + * + * @return -1 if the specified byte is not found + */ + public abstract int indexOf(byte b); + + // //////////////////////// + // Skip or fill methods // + // //////////////////////// + + /** + * Forwards the position of this buffer as the specified size + * bytes. + */ + public abstract IoBuffer skip(int size); + + /** + * Fills this buffer with the specified value. This method moves buffer + * position forward. + */ + public abstract IoBuffer fill(byte value, int size); + + /** + * Fills this buffer with the specified value. This method does not change + * buffer position. + */ + public abstract IoBuffer fillAndReset(byte value, int size); + + /** + * Fills this buffer with NUL (0x00). This method moves buffer + * position forward. + */ + public abstract IoBuffer fill(int size); + + /** + * Fills this buffer with NUL (0x00). This method does not + * change buffer position. + */ + public abstract IoBuffer fillAndReset(int size); + + // //////////////////////// + // Enum methods // + // //////////////////////// + + /** + * Reads a byte from the buffer and returns the correlating enum constant + * defined by the specified enum type. + * + * @param + * The enum type to return + * @param enumClass + * The enum's class object + */ + public abstract > E getEnum(Class enumClass); + + /** + * Reads a byte from the buffer and returns the correlating enum constant + * defined by the specified enum type. + * + * @param + * The enum type to return + * @param index + * the index from which the byte will be read + * @param enumClass + * The enum's class object + */ + public abstract > E getEnum(int index, + Class enumClass); + + /** + * Reads a short from the buffer and returns the correlating enum constant + * defined by the specified enum type. + * + * @param + * The enum type to return + * @param enumClass + * The enum's class object + */ + public abstract > E getEnumShort(Class enumClass); + + /** + * Reads a short from the buffer and returns the correlating enum constant + * defined by the specified enum type. + * + * @param + * The enum type to return + * @param index + * the index from which the bytes will be read + * @param enumClass + * The enum's class object + */ + public abstract > E getEnumShort(int index, + Class enumClass); + + /** + * Reads an int from the buffer and returns the correlating enum constant + * defined by the specified enum type. + * + * @param + * The enum type to return + * @param enumClass + * The enum's class object + */ + public abstract > E getEnumInt(Class enumClass); + + /** + * Reads an int from the buffer and returns the correlating enum constant + * defined by the specified enum type. + * + * @param + * The enum type to return + * @param index + * the index from which the bytes will be read + * @param enumClass + * The enum's class object + */ + public abstract > E getEnumInt(int index, + Class enumClass); + + /** + * Writes an enum's ordinal value to the buffer as a byte. + * + * @param e + * The enum to write to the buffer + */ + public abstract IoBuffer putEnum(Enum e); + + /** + * Writes an enum's ordinal value to the buffer as a byte. + * + * @param index + * The index at which the byte will be written + * @param e + * The enum to write to the buffer + */ + public abstract IoBuffer putEnum(int index, Enum e); + + /** + * Writes an enum's ordinal value to the buffer as a short. + * + * @param e + * The enum to write to the buffer + */ + public abstract IoBuffer putEnumShort(Enum e); + + /** + * Writes an enum's ordinal value to the buffer as a short. + * + * @param index + * The index at which the bytes will be written + * @param e + * The enum to write to the buffer + */ + public abstract IoBuffer putEnumShort(int index, Enum e); + + /** + * Writes an enum's ordinal value to the buffer as an integer. + * + * @param e + * The enum to write to the buffer + */ + public abstract IoBuffer putEnumInt(Enum e); + + /** + * Writes an enum's ordinal value to the buffer as an integer. + * + * @param index + * The index at which the bytes will be written + * @param e + * The enum to write to the buffer + */ + public abstract IoBuffer putEnumInt(int index, Enum e); + + // //////////////////////// + // EnumSet methods // + // //////////////////////// + + /** + * Reads a byte sized bit vector and converts it to an {@link EnumSet}. + * + *

+ * Each bit is mapped to a value in the specified enum. The least + * significant bit maps to the first entry in the specified enum and each + * subsequent bit maps to each subsequent bit as mapped to the subsequent + * enum value. + *

+ * + * @param + * the enum type + * @param enumClass + * the enum class used to create the EnumSet + * @return the EnumSet representation of the bit vector + */ + public abstract > EnumSet getEnumSet( + Class enumClass); + + /** + * Reads a byte sized bit vector and converts it to an {@link EnumSet}. + * + * @see #getEnumSet(Class) + * @param + * the enum type + * @param index + * the index from which the byte will be read + * @param enumClass + * the enum class used to create the EnumSet + * @return the EnumSet representation of the bit vector + */ + public abstract > EnumSet getEnumSet(int index, + Class enumClass); + + /** + * Reads a short sized bit vector and converts it to an {@link EnumSet}. + * + * @see #getEnumSet(Class) + * @param + * the enum type + * @param enumClass + * the enum class used to create the EnumSet + * @return the EnumSet representation of the bit vector + */ + public abstract > EnumSet getEnumSetShort( + Class enumClass); + + /** + * Reads a short sized bit vector and converts it to an {@link EnumSet}. + * + * @see #getEnumSet(Class) + * @param + * the enum type + * @param index + * the index from which the bytes will be read + * @param enumClass + * the enum class used to create the EnumSet + * @return the EnumSet representation of the bit vector + */ + public abstract > EnumSet getEnumSetShort(int index, + Class enumClass); + + /** + * Reads an int sized bit vector and converts it to an {@link EnumSet}. + * + * @see #getEnumSet(Class) + * @param + * the enum type + * @param enumClass + * the enum class used to create the EnumSet + * @return the EnumSet representation of the bit vector + */ + public abstract > EnumSet getEnumSetInt( + Class enumClass); + + /** + * Reads an int sized bit vector and converts it to an {@link EnumSet}. + * + * @see #getEnumSet(Class) + * @param + * the enum type + * @param index + * the index from which the bytes will be read + * @param enumClass + * the enum class used to create the EnumSet + * @return the EnumSet representation of the bit vector + */ + public abstract > EnumSet getEnumSetInt(int index, + Class enumClass); + + /** + * Reads a long sized bit vector and converts it to an {@link EnumSet}. + * + * @see #getEnumSet(Class) + * @param + * the enum type + * @param enumClass + * the enum class used to create the EnumSet + * @return the EnumSet representation of the bit vector + */ + public abstract > EnumSet getEnumSetLong( + Class enumClass); + + /** + * Reads a long sized bit vector and converts it to an {@link EnumSet}. + * + * @see #getEnumSet(Class) + * @param + * the enum type + * @param index + * the index from which the bytes will be read + * @param enumClass + * the enum class used to create the EnumSet + * @return the EnumSet representation of the bit vector + */ + public abstract > EnumSet getEnumSetLong(int index, + Class enumClass); + + /** + * Writes the specified {@link Set} to the buffer as a byte sized bit + * vector. + * + * @param + * the enum type of the Set + * @param set + * the enum set to write to the buffer + */ + public abstract > IoBuffer putEnumSet(Set set); + + /** + * Writes the specified {@link Set} to the buffer as a byte sized bit + * vector. + * + * @param + * the enum type of the Set + * @param index + * the index at which the byte will be written + * @param set + * the enum set to write to the buffer + */ + public abstract > IoBuffer putEnumSet(int index, + Set set); + + /** + * Writes the specified {@link Set} to the buffer as a short sized bit + * vector. + * + * @param + * the enum type of the Set + * @param set + * the enum set to write to the buffer + */ + public abstract > IoBuffer putEnumSetShort(Set set); + + /** + * Writes the specified {@link Set} to the buffer as a short sized bit + * vector. + * + * @param + * the enum type of the Set + * @param index + * the index at which the bytes will be written + * @param set + * the enum set to write to the buffer + */ + public abstract > IoBuffer putEnumSetShort(int index, + Set set); + + /** + * Writes the specified {@link Set} to the buffer as an int sized bit + * vector. + * + * @param + * the enum type of the Set + * @param set + * the enum set to write to the buffer + */ + public abstract > IoBuffer putEnumSetInt(Set set); + + /** + * Writes the specified {@link Set} to the buffer as an int sized bit + * vector. + * + * @param + * the enum type of the Set + * @param index + * the index at which the bytes will be written + * @param set + * the enum set to write to the buffer + */ + public abstract > IoBuffer putEnumSetInt(int index, + Set set); + + /** + * Writes the specified {@link Set} to the buffer as a long sized bit + * vector. + * + * @param + * the enum type of the Set + * @param set + * the enum set to write to the buffer + */ + public abstract > IoBuffer putEnumSetLong(Set set); + + /** + * Writes the specified {@link Set} to the buffer as a long sized bit + * vector. + * + * @param + * the enum type of the Set + * @param index + * the index at which the bytes will be written + * @param set + * the enum set to write to the buffer + */ + public abstract > IoBuffer putEnumSetLong(int index, + Set set); } diff --git a/src/main/java/com/google/code/yanf4j/buffer/IoBufferAllocator.java b/src/main/java/com/google/code/yanf4j/buffer/IoBufferAllocator.java index a3386492a..48c825862 100644 --- a/src/main/java/com/google/code/yanf4j/buffer/IoBufferAllocator.java +++ b/src/main/java/com/google/code/yanf4j/buffer/IoBufferAllocator.java @@ -21,7 +21,6 @@ import java.nio.ByteBuffer; - /** * Allocates {@link IoBuffer}s and manages them. Please implement this interface * if you need more advanced memory management scheme. @@ -31,38 +30,35 @@ * $ */ public interface IoBufferAllocator { - /** - * Returns the buffer which is capable of the specified size. - * - * @param capacity - * the capacity of the buffer - * @param direct - * true to get a direct buffer, false to get a - * heap buffer. - */ - IoBuffer allocate(int capacity, boolean direct); - - - /** - * Returns the NIO buffer which is capable of the specified size. - * - * @param capacity - * the capacity of the buffer - * @param direct - * true to get a direct buffer, false to get a - * heap buffer. - */ - ByteBuffer allocateNioBuffer(int capacity, boolean direct); - + /** + * Returns the buffer which is capable of the specified size. + * + * @param capacity + * the capacity of the buffer + * @param direct + * true to get a direct buffer, false to get a + * heap buffer. + */ + IoBuffer allocate(int capacity, boolean direct); - /** - * Wraps the specified NIO {@link ByteBuffer} into MINA buffer. - */ - IoBuffer wrap(ByteBuffer nioBuffer); + /** + * Returns the NIO buffer which is capable of the specified size. + * + * @param capacity + * the capacity of the buffer + * @param direct + * true to get a direct buffer, false to get a + * heap buffer. + */ + ByteBuffer allocateNioBuffer(int capacity, boolean direct); + /** + * Wraps the specified NIO {@link ByteBuffer} into MINA buffer. + */ + IoBuffer wrap(ByteBuffer nioBuffer); - /** - * Dispose of this allocator. - */ - void dispose(); + /** + * Dispose of this allocator. + */ + void dispose(); } diff --git a/src/main/java/com/google/code/yanf4j/buffer/IoBufferHexDumper.java b/src/main/java/com/google/code/yanf4j/buffer/IoBufferHexDumper.java index 903f1a11b..4a011f331 100644 --- a/src/main/java/com/google/code/yanf4j/buffer/IoBufferHexDumper.java +++ b/src/main/java/com/google/code/yanf4j/buffer/IoBufferHexDumper.java @@ -29,88 +29,88 @@ */ class IoBufferHexDumper { - /** - * The high digits lookup table. - */ - private static final byte[] highDigits; - - /** - * The low digits lookup table. - */ - private static final byte[] lowDigits; - - /** - * Initialize lookup tables. - */ - static { - final byte[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; - - int i; - byte[] high = new byte[256]; - byte[] low = new byte[256]; - - for (i = 0; i < 256; i++) { - high[i] = digits[i >>> 4]; - low[i] = digits[i & 0x0F]; - } - - highDigits = high; - lowDigits = low; - } - - - /** - * Dumps an {@link IoBuffer} to a hex formatted string. - * - * @param in - * the buffer to dump - * @param lengthLimit - * the limit at which hex dumping will stop - * @return a hex formatted string representation of the in - * {@link Iobuffer}. - */ - public static String getHexdump(IoBuffer in, int lengthLimit) { - if (lengthLimit == 0) { - throw new IllegalArgumentException("lengthLimit: " + lengthLimit + " (expected: 1+)"); - } - - boolean truncate = in.remaining() > lengthLimit; - int size; - if (truncate) { - size = lengthLimit; - } - else { - size = in.remaining(); - } - - if (size == 0) { - return "empty"; - } - - StringBuilder out = new StringBuilder(in.remaining() * 3 - 1); - - int mark = in.position(); - - // fill the first - int byteValue = in.get() & 0xFF; - out.append((char) highDigits[byteValue]); - out.append((char) lowDigits[byteValue]); - size--; - - // and the others, too - for (; size > 0; size--) { - out.append(' '); - byteValue = in.get() & 0xFF; - out.append((char) highDigits[byteValue]); - out.append((char) lowDigits[byteValue]); - } - - in.position(mark); - - if (truncate) { - out.append("..."); - } - - return out.toString(); - } + /** + * The high digits lookup table. + */ + private static final byte[] highDigits; + + /** + * The low digits lookup table. + */ + private static final byte[] lowDigits; + + /** + * Initialize lookup tables. + */ + static { + final byte[] digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F'}; + + int i; + byte[] high = new byte[256]; + byte[] low = new byte[256]; + + for (i = 0; i < 256; i++) { + high[i] = digits[i >>> 4]; + low[i] = digits[i & 0x0F]; + } + + highDigits = high; + lowDigits = low; + } + + /** + * Dumps an {@link IoBuffer} to a hex formatted string. + * + * @param in + * the buffer to dump + * @param lengthLimit + * the limit at which hex dumping will stop + * @return a hex formatted string representation of the in + * {@link Iobuffer}. + */ + public static String getHexdump(IoBuffer in, int lengthLimit) { + if (lengthLimit == 0) { + throw new IllegalArgumentException( + "lengthLimit: " + lengthLimit + " (expected: 1+)"); + } + + boolean truncate = in.remaining() > lengthLimit; + int size; + if (truncate) { + size = lengthLimit; + } else { + size = in.remaining(); + } + + if (size == 0) { + return "empty"; + } + + StringBuilder out = new StringBuilder(in.remaining() * 3 - 1); + + int mark = in.position(); + + // fill the first + int byteValue = in.get() & 0xFF; + out.append((char) highDigits[byteValue]); + out.append((char) lowDigits[byteValue]); + size--; + + // and the others, too + for (; size > 0; size--) { + out.append(' '); + byteValue = in.get() & 0xFF; + out.append((char) highDigits[byteValue]); + out.append((char) lowDigits[byteValue]); + } + + in.position(mark); + + if (truncate) { + out.append("..."); + } + + return out.toString(); + } } \ No newline at end of file diff --git a/src/main/java/com/google/code/yanf4j/buffer/IoBufferWrapper.java b/src/main/java/com/google/code/yanf4j/buffer/IoBufferWrapper.java index c6319c876..75260c658 100644 --- a/src/main/java/com/google/code/yanf4j/buffer/IoBufferWrapper.java +++ b/src/main/java/com/google/code/yanf4j/buffer/IoBufferWrapper.java @@ -36,7 +36,6 @@ import java.util.EnumSet; import java.util.Set; - /** * A {@link IoBuffer} that wraps a buffer and proxies any operations to it. *

@@ -50,998 +49,860 @@ */ public class IoBufferWrapper extends IoBuffer { - /** - * The buffer proxied by this proxy. - */ - private final IoBuffer buf; - - - /** - * Create a new instance. - * - * @param buf - * the buffer to be proxied - */ - protected IoBufferWrapper(IoBuffer buf) { - if (buf == null) { - throw new NullPointerException("buf"); - } - this.buf = buf; - } - - - /** - * Returns the parent buffer that this buffer wrapped. - */ - public IoBuffer getParentBuffer() { - return buf; - } - - - @Override - public boolean isDirect() { - return buf.isDirect(); - } - - - @Override - public ByteBuffer buf() { - return buf.buf(); - } - - - @Override - public int capacity() { - return buf.capacity(); - } - - - @Override - public int position() { - return buf.position(); - } - - - @Override - public IoBuffer position(int newPosition) { - buf.position(newPosition); - return this; - } - - - @Override - public int limit() { - return buf.limit(); - } - - - @Override - public IoBuffer limit(int newLimit) { - buf.limit(newLimit); - return this; - } - - - @Override - public IoBuffer mark() { - buf.mark(); - return this; - } - - - @Override - public IoBuffer reset() { - buf.reset(); - return this; - } - - - @Override - public IoBuffer clear() { - buf.clear(); - return this; - } - - - @Override - public IoBuffer sweep() { - buf.sweep(); - return this; - } - - - @Override - public IoBuffer sweep(byte value) { - buf.sweep(value); - return this; - } - - - @Override - public IoBuffer flip() { - buf.flip(); - return this; - } - - - @Override - public IoBuffer rewind() { - buf.rewind(); - return this; - } - - - @Override - public int remaining() { - return buf.remaining(); - } - - - @Override - public boolean hasRemaining() { - return buf.hasRemaining(); - } - - - @Override - public byte get() { - return buf.get(); - } - - - @Override - public short getUnsigned() { - return buf.getUnsigned(); - } - - - @Override - public IoBuffer put(byte b) { - buf.put(b); - return this; - } - - - @Override - public byte get(int index) { - return buf.get(index); - } - - - @Override - public short getUnsigned(int index) { - return buf.getUnsigned(index); - } - - - @Override - public IoBuffer put(int index, byte b) { - buf.put(index, b); - return this; - } - - - @Override - public IoBuffer get(byte[] dst, int offset, int length) { - buf.get(dst, offset, length); - return this; - } - - - @Override - public IoBuffer getSlice(int index, int length) { - return buf.getSlice(index, length); - } - - - @Override - public IoBuffer getSlice(int length) { - return buf.getSlice(length); - } - - - @Override - public IoBuffer get(byte[] dst) { - buf.get(dst); - return this; - } - - - @Override - public IoBuffer put(IoBuffer src) { - buf.put(src); - return this; - } - - - @Override - public IoBuffer put(ByteBuffer src) { - buf.put(src); - return this; - } - - - @Override - public IoBuffer put(byte[] src, int offset, int length) { - buf.put(src, offset, length); - return this; - } - - - @Override - public IoBuffer put(byte[] src) { - buf.put(src); - return this; - } - - - @Override - public IoBuffer compact() { - buf.compact(); - return this; - } - - - @Override - public String toString() { - return buf.toString(); - } - - - @Override - public int hashCode() { - return buf.hashCode(); - } - - - @Override - public boolean equals(Object ob) { - return buf.equals(ob); - } - - - public int compareTo(IoBuffer that) { - return buf.compareTo(that); - } - - - @Override - public ByteOrder order() { - return buf.order(); - } - - - @Override - public IoBuffer order(ByteOrder bo) { - buf.order(bo); - return this; - } - - - @Override - public char getChar() { - return buf.getChar(); - } - - - @Override - public IoBuffer putChar(char value) { - buf.putChar(value); - return this; - } - - - @Override - public char getChar(int index) { - return buf.getChar(index); - } - - - @Override - public IoBuffer putChar(int index, char value) { - buf.putChar(index, value); - return this; - } - - - @Override - public CharBuffer asCharBuffer() { - return buf.asCharBuffer(); - } - - - @Override - public short getShort() { - return buf.getShort(); - } - - - @Override - public int getUnsignedShort() { - return buf.getUnsignedShort(); - } - - - @Override - public IoBuffer putShort(short value) { - buf.putShort(value); - return this; - } - - - @Override - public short getShort(int index) { - return buf.getShort(index); - } - - - @Override - public int getUnsignedShort(int index) { - return buf.getUnsignedShort(index); - } - - - @Override - public IoBuffer putShort(int index, short value) { - buf.putShort(index, value); - return this; - } - - - @Override - public ShortBuffer asShortBuffer() { - return buf.asShortBuffer(); - } - - - @Override - public int getInt() { - return buf.getInt(); - } - - - @Override - public long getUnsignedInt() { - return buf.getUnsignedInt(); - } - - - @Override - public IoBuffer putInt(int value) { - buf.putInt(value); - return this; - } - - - @Override - public int getInt(int index) { - return buf.getInt(index); - } - - - @Override - public long getUnsignedInt(int index) { - return buf.getUnsignedInt(index); - } - - - @Override - public IoBuffer putInt(int index, int value) { - buf.putInt(index, value); - return this; - } - - - @Override - public IntBuffer asIntBuffer() { - return buf.asIntBuffer(); - } - - - @Override - public long getLong() { - return buf.getLong(); - } - - - @Override - public IoBuffer putLong(long value) { - buf.putLong(value); - return this; - } - - - @Override - public long getLong(int index) { - return buf.getLong(index); - } - - - @Override - public IoBuffer putLong(int index, long value) { - buf.putLong(index, value); - return this; - } - - - @Override - public LongBuffer asLongBuffer() { - return buf.asLongBuffer(); - } - - - @Override - public float getFloat() { - return buf.getFloat(); - } - - - @Override - public IoBuffer putFloat(float value) { - buf.putFloat(value); - return this; - } - - - @Override - public float getFloat(int index) { - return buf.getFloat(index); - } - - - @Override - public IoBuffer putFloat(int index, float value) { - buf.putFloat(index, value); - return this; - } - - - @Override - public FloatBuffer asFloatBuffer() { - return buf.asFloatBuffer(); - } - - - @Override - public double getDouble() { - return buf.getDouble(); - } - - - @Override - public IoBuffer putDouble(double value) { - buf.putDouble(value); - return this; - } - - - @Override - public double getDouble(int index) { - return buf.getDouble(index); - } - - - @Override - public IoBuffer putDouble(int index, double value) { - buf.putDouble(index, value); - return this; - } - - - @Override - public DoubleBuffer asDoubleBuffer() { - return buf.asDoubleBuffer(); - } - - - @Override - public String getHexDump() { - return buf.getHexDump(); - } - - - @Override - public String getString(int fieldSize, CharsetDecoder decoder) throws CharacterCodingException { - return buf.getString(fieldSize, decoder); - } - - - @Override - public String getString(CharsetDecoder decoder) throws CharacterCodingException { - return buf.getString(decoder); - } - - - @Override - public String getPrefixedString(CharsetDecoder decoder) throws CharacterCodingException { - return buf.getPrefixedString(decoder); - } - - - @Override - public String getPrefixedString(int prefixLength, CharsetDecoder decoder) throws CharacterCodingException { - return buf.getPrefixedString(prefixLength, decoder); - } - - - @Override - public IoBuffer putString(CharSequence in, int fieldSize, CharsetEncoder encoder) throws CharacterCodingException { - buf.putString(in, fieldSize, encoder); - return this; - } - - - @Override - public IoBuffer putString(CharSequence in, CharsetEncoder encoder) throws CharacterCodingException { - buf.putString(in, encoder); - return this; - } - - - @Override - public IoBuffer putPrefixedString(CharSequence in, CharsetEncoder encoder) throws CharacterCodingException { - buf.putPrefixedString(in, encoder); - return this; - } - - - @Override - public IoBuffer putPrefixedString(CharSequence in, int prefixLength, CharsetEncoder encoder) - throws CharacterCodingException { - buf.putPrefixedString(in, prefixLength, encoder); - return this; - } - - - @Override - public IoBuffer putPrefixedString(CharSequence in, int prefixLength, int padding, CharsetEncoder encoder) - throws CharacterCodingException { - buf.putPrefixedString(in, prefixLength, padding, encoder); - return this; - } - - - @Override - public IoBuffer putPrefixedString(CharSequence in, int prefixLength, int padding, byte padValue, - CharsetEncoder encoder) throws CharacterCodingException { - buf.putPrefixedString(in, prefixLength, padding, padValue, encoder); - return this; - } - - - @Override - public IoBuffer skip(int size) { - buf.skip(size); - return this; - } - - - @Override - public IoBuffer fill(byte value, int size) { - buf.fill(value, size); - return this; - } - - - @Override - public IoBuffer fillAndReset(byte value, int size) { - buf.fillAndReset(value, size); - return this; - } - - - @Override - public IoBuffer fill(int size) { - buf.fill(size); - return this; - } - - - @Override - public IoBuffer fillAndReset(int size) { - buf.fillAndReset(size); - return this; - } - - - @Override - public boolean isAutoExpand() { - return buf.isAutoExpand(); - } - - - @Override - public IoBuffer setAutoExpand(boolean autoExpand) { - buf.setAutoExpand(autoExpand); - return this; - } - - - @Override - public IoBuffer expand(int pos, int expectedRemaining) { - buf.expand(pos, expectedRemaining); - return this; - } - - - @Override - public IoBuffer expand(int expectedRemaining) { - buf.expand(expectedRemaining); - return this; - } - - - @Override - public Object getObject() throws ClassNotFoundException { - return buf.getObject(); - } - - - @Override - public Object getObject(ClassLoader classLoader) throws ClassNotFoundException { - return buf.getObject(classLoader); - } - - - @Override - public IoBuffer putObject(Object o) { - buf.putObject(o); - return this; - } - - - @Override - public InputStream asInputStream() { - return buf.asInputStream(); - } - - - @Override - public OutputStream asOutputStream() { - return buf.asOutputStream(); - } - - - @Override - public IoBuffer duplicate() { - return buf.duplicate(); - } - - - @Override - public IoBuffer slice() { - return buf.slice(); - } - - - @Override - public IoBuffer asReadOnlyBuffer() { - return buf.asReadOnlyBuffer(); - } - - - @Override - public byte[] array() { - return buf.array(); - } - - - @Override - public int arrayOffset() { - return buf.arrayOffset(); - } - - - @Override - public int minimumCapacity() { - return buf.minimumCapacity(); - } - - - @Override - public IoBuffer minimumCapacity(int minimumCapacity) { - buf.minimumCapacity(minimumCapacity); - return this; - } - - - @Override - public IoBuffer capacity(int newCapacity) { - buf.capacity(newCapacity); - return this; - } - - - @Override - public boolean isReadOnly() { - return buf.isReadOnly(); - } - - - @Override - public int markValue() { - return buf.markValue(); - } - - - @Override - public boolean hasArray() { - return buf.hasArray(); - } - - - @Override - public void free() { - buf.free(); - } - - - @Override - public boolean isDerived() { - return buf.isDerived(); - } - - - @Override - public boolean isAutoShrink() { - return buf.isAutoShrink(); - } - - - @Override - public IoBuffer setAutoShrink(boolean autoShrink) { - buf.setAutoShrink(autoShrink); - return this; - } - - - @Override - public IoBuffer shrink() { - buf.shrink(); - return this; - } - - - @Override - public int getMediumInt() { - return buf.getMediumInt(); - } - - - @Override - public int getUnsignedMediumInt() { - return buf.getUnsignedMediumInt(); - } - - - @Override - public int getMediumInt(int index) { - return buf.getMediumInt(index); - } - - - @Override - public int getUnsignedMediumInt(int index) { - return buf.getUnsignedMediumInt(index); - } - - - @Override - public IoBuffer putMediumInt(int value) { - buf.putMediumInt(value); - return this; - } - - - @Override - public IoBuffer putMediumInt(int index, int value) { - buf.putMediumInt(index, value); - return this; - } - - - @Override - public String getHexDump(int lengthLimit) { - return buf.getHexDump(lengthLimit); - } - - - @Override - public boolean prefixedDataAvailable(int prefixLength) { - return buf.prefixedDataAvailable(prefixLength); - } - - - @Override - public boolean prefixedDataAvailable(int prefixLength, int maxDataLength) { - return buf.prefixedDataAvailable(prefixLength, maxDataLength); - } - - - @Override - public int indexOf(byte b) { - return buf.indexOf(b); - } - - - @Override - public > E getEnum(Class enumClass) { - return buf.getEnum(enumClass); - } - - - @Override - public > E getEnum(int index, Class enumClass) { - return buf.getEnum(index, enumClass); - } - - - @Override - public > E getEnumShort(Class enumClass) { - return buf.getEnumShort(enumClass); - } - - - @Override - public > E getEnumShort(int index, Class enumClass) { - return buf.getEnumShort(index, enumClass); - } - - - @Override - public > E getEnumInt(Class enumClass) { - return buf.getEnumInt(enumClass); - } - - - @Override - public > E getEnumInt(int index, Class enumClass) { - return buf.getEnumInt(index, enumClass); - } - - - @Override - public IoBuffer putEnum(Enum e) { - buf.putEnum(e); - return this; - } - - - @Override - public IoBuffer putEnum(int index, Enum e) { - buf.putEnum(index, e); - return this; - } - - - @Override - public IoBuffer putEnumShort(Enum e) { - buf.putEnumShort(e); - return this; - } - - - @Override - public IoBuffer putEnumShort(int index, Enum e) { - buf.putEnumShort(index, e); - return this; - } - - - @Override - public IoBuffer putEnumInt(Enum e) { - buf.putEnumInt(e); - return this; - } - - - @Override - public IoBuffer putEnumInt(int index, Enum e) { - buf.putEnumInt(index, e); - return this; - } - - - @Override - public > EnumSet getEnumSet(Class enumClass) { - return buf.getEnumSet(enumClass); - } - - - @Override - public > EnumSet getEnumSet(int index, Class enumClass) { - return buf.getEnumSet(index, enumClass); - } - - - @Override - public > EnumSet getEnumSetShort(Class enumClass) { - return buf.getEnumSetShort(enumClass); - } - - - @Override - public > EnumSet getEnumSetShort(int index, Class enumClass) { - return buf.getEnumSetShort(index, enumClass); - } - - - @Override - public > EnumSet getEnumSetInt(Class enumClass) { - return buf.getEnumSetInt(enumClass); - } - - - @Override - public > EnumSet getEnumSetInt(int index, Class enumClass) { - return buf.getEnumSetInt(index, enumClass); - } - - - @Override - public > EnumSet getEnumSetLong(Class enumClass) { - return buf.getEnumSetLong(enumClass); - } - - - @Override - public > EnumSet getEnumSetLong(int index, Class enumClass) { - return buf.getEnumSetLong(index, enumClass); - } - - - @Override - public > IoBuffer putEnumSet(Set set) { - buf.putEnumSet(set); - return this; - } - - - @Override - public > IoBuffer putEnumSet(int index, Set set) { - buf.putEnumSet(index, set); - return this; - } - - - @Override - public > IoBuffer putEnumSetShort(Set set) { - buf.putEnumSetShort(set); - return this; - } - - - @Override - public > IoBuffer putEnumSetShort(int index, Set set) { - buf.putEnumSetShort(index, set); - return this; - } - - - @Override - public > IoBuffer putEnumSetInt(Set set) { - buf.putEnumSetInt(set); - return this; - } - - - @Override - public > IoBuffer putEnumSetInt(int index, Set set) { - buf.putEnumSetInt(index, set); - return this; - } - - - @Override - public > IoBuffer putEnumSetLong(Set set) { - buf.putEnumSetLong(set); - return this; - } - - - @Override - public > IoBuffer putEnumSetLong(int index, Set set) { - buf.putEnumSetLong(index, set); - return this; - } + /** + * The buffer proxied by this proxy. + */ + private final IoBuffer buf; + + /** + * Create a new instance. + * + * @param buf + * the buffer to be proxied + */ + protected IoBufferWrapper(IoBuffer buf) { + if (buf == null) { + throw new NullPointerException("buf"); + } + this.buf = buf; + } + + /** + * Returns the parent buffer that this buffer wrapped. + */ + public IoBuffer getParentBuffer() { + return buf; + } + + @Override + public boolean isDirect() { + return buf.isDirect(); + } + + @Override + public ByteBuffer buf() { + return buf.buf(); + } + + @Override + public int capacity() { + return buf.capacity(); + } + + @Override + public int position() { + return buf.position(); + } + + @Override + public IoBuffer position(int newPosition) { + buf.position(newPosition); + return this; + } + + @Override + public int limit() { + return buf.limit(); + } + + @Override + public IoBuffer limit(int newLimit) { + buf.limit(newLimit); + return this; + } + + @Override + public IoBuffer mark() { + buf.mark(); + return this; + } + + @Override + public IoBuffer reset() { + buf.reset(); + return this; + } + + @Override + public IoBuffer clear() { + buf.clear(); + return this; + } + + @Override + public IoBuffer sweep() { + buf.sweep(); + return this; + } + + @Override + public IoBuffer sweep(byte value) { + buf.sweep(value); + return this; + } + + @Override + public IoBuffer flip() { + buf.flip(); + return this; + } + + @Override + public IoBuffer rewind() { + buf.rewind(); + return this; + } + + @Override + public int remaining() { + return buf.remaining(); + } + + @Override + public boolean hasRemaining() { + return buf.hasRemaining(); + } + + @Override + public byte get() { + return buf.get(); + } + + @Override + public short getUnsigned() { + return buf.getUnsigned(); + } + + @Override + public IoBuffer put(byte b) { + buf.put(b); + return this; + } + + @Override + public byte get(int index) { + return buf.get(index); + } + + @Override + public short getUnsigned(int index) { + return buf.getUnsigned(index); + } + + @Override + public IoBuffer put(int index, byte b) { + buf.put(index, b); + return this; + } + + @Override + public IoBuffer get(byte[] dst, int offset, int length) { + buf.get(dst, offset, length); + return this; + } + + @Override + public IoBuffer getSlice(int index, int length) { + return buf.getSlice(index, length); + } + + @Override + public IoBuffer getSlice(int length) { + return buf.getSlice(length); + } + + @Override + public IoBuffer get(byte[] dst) { + buf.get(dst); + return this; + } + + @Override + public IoBuffer put(IoBuffer src) { + buf.put(src); + return this; + } + + @Override + public IoBuffer put(ByteBuffer src) { + buf.put(src); + return this; + } + + @Override + public IoBuffer put(byte[] src, int offset, int length) { + buf.put(src, offset, length); + return this; + } + + @Override + public IoBuffer put(byte[] src) { + buf.put(src); + return this; + } + + @Override + public IoBuffer compact() { + buf.compact(); + return this; + } + + @Override + public String toString() { + return buf.toString(); + } + + @Override + public int hashCode() { + return buf.hashCode(); + } + + @Override + public boolean equals(Object ob) { + return buf.equals(ob); + } + + public int compareTo(IoBuffer that) { + return buf.compareTo(that); + } + + @Override + public ByteOrder order() { + return buf.order(); + } + + @Override + public IoBuffer order(ByteOrder bo) { + buf.order(bo); + return this; + } + + @Override + public char getChar() { + return buf.getChar(); + } + + @Override + public IoBuffer putChar(char value) { + buf.putChar(value); + return this; + } + + @Override + public char getChar(int index) { + return buf.getChar(index); + } + + @Override + public IoBuffer putChar(int index, char value) { + buf.putChar(index, value); + return this; + } + + @Override + public CharBuffer asCharBuffer() { + return buf.asCharBuffer(); + } + + @Override + public short getShort() { + return buf.getShort(); + } + + @Override + public int getUnsignedShort() { + return buf.getUnsignedShort(); + } + + @Override + public IoBuffer putShort(short value) { + buf.putShort(value); + return this; + } + + @Override + public short getShort(int index) { + return buf.getShort(index); + } + + @Override + public int getUnsignedShort(int index) { + return buf.getUnsignedShort(index); + } + + @Override + public IoBuffer putShort(int index, short value) { + buf.putShort(index, value); + return this; + } + + @Override + public ShortBuffer asShortBuffer() { + return buf.asShortBuffer(); + } + + @Override + public int getInt() { + return buf.getInt(); + } + + @Override + public long getUnsignedInt() { + return buf.getUnsignedInt(); + } + + @Override + public IoBuffer putInt(int value) { + buf.putInt(value); + return this; + } + + @Override + public int getInt(int index) { + return buf.getInt(index); + } + + @Override + public long getUnsignedInt(int index) { + return buf.getUnsignedInt(index); + } + + @Override + public IoBuffer putInt(int index, int value) { + buf.putInt(index, value); + return this; + } + + @Override + public IntBuffer asIntBuffer() { + return buf.asIntBuffer(); + } + + @Override + public long getLong() { + return buf.getLong(); + } + + @Override + public IoBuffer putLong(long value) { + buf.putLong(value); + return this; + } + + @Override + public long getLong(int index) { + return buf.getLong(index); + } + + @Override + public IoBuffer putLong(int index, long value) { + buf.putLong(index, value); + return this; + } + + @Override + public LongBuffer asLongBuffer() { + return buf.asLongBuffer(); + } + + @Override + public float getFloat() { + return buf.getFloat(); + } + + @Override + public IoBuffer putFloat(float value) { + buf.putFloat(value); + return this; + } + + @Override + public float getFloat(int index) { + return buf.getFloat(index); + } + + @Override + public IoBuffer putFloat(int index, float value) { + buf.putFloat(index, value); + return this; + } + + @Override + public FloatBuffer asFloatBuffer() { + return buf.asFloatBuffer(); + } + + @Override + public double getDouble() { + return buf.getDouble(); + } + + @Override + public IoBuffer putDouble(double value) { + buf.putDouble(value); + return this; + } + + @Override + public double getDouble(int index) { + return buf.getDouble(index); + } + + @Override + public IoBuffer putDouble(int index, double value) { + buf.putDouble(index, value); + return this; + } + + @Override + public DoubleBuffer asDoubleBuffer() { + return buf.asDoubleBuffer(); + } + + @Override + public String getHexDump() { + return buf.getHexDump(); + } + + @Override + public String getString(int fieldSize, CharsetDecoder decoder) + throws CharacterCodingException { + return buf.getString(fieldSize, decoder); + } + + @Override + public String getString(CharsetDecoder decoder) + throws CharacterCodingException { + return buf.getString(decoder); + } + + @Override + public String getPrefixedString(CharsetDecoder decoder) + throws CharacterCodingException { + return buf.getPrefixedString(decoder); + } + + @Override + public String getPrefixedString(int prefixLength, CharsetDecoder decoder) + throws CharacterCodingException { + return buf.getPrefixedString(prefixLength, decoder); + } + + @Override + public IoBuffer putString(CharSequence in, int fieldSize, + CharsetEncoder encoder) throws CharacterCodingException { + buf.putString(in, fieldSize, encoder); + return this; + } + + @Override + public IoBuffer putString(CharSequence in, CharsetEncoder encoder) + throws CharacterCodingException { + buf.putString(in, encoder); + return this; + } + + @Override + public IoBuffer putPrefixedString(CharSequence in, CharsetEncoder encoder) + throws CharacterCodingException { + buf.putPrefixedString(in, encoder); + return this; + } + + @Override + public IoBuffer putPrefixedString(CharSequence in, int prefixLength, + CharsetEncoder encoder) throws CharacterCodingException { + buf.putPrefixedString(in, prefixLength, encoder); + return this; + } + + @Override + public IoBuffer putPrefixedString(CharSequence in, int prefixLength, + int padding, CharsetEncoder encoder) + throws CharacterCodingException { + buf.putPrefixedString(in, prefixLength, padding, encoder); + return this; + } + + @Override + public IoBuffer putPrefixedString(CharSequence in, int prefixLength, + int padding, byte padValue, CharsetEncoder encoder) + throws CharacterCodingException { + buf.putPrefixedString(in, prefixLength, padding, padValue, encoder); + return this; + } + + @Override + public IoBuffer skip(int size) { + buf.skip(size); + return this; + } + + @Override + public IoBuffer fill(byte value, int size) { + buf.fill(value, size); + return this; + } + + @Override + public IoBuffer fillAndReset(byte value, int size) { + buf.fillAndReset(value, size); + return this; + } + + @Override + public IoBuffer fill(int size) { + buf.fill(size); + return this; + } + + @Override + public IoBuffer fillAndReset(int size) { + buf.fillAndReset(size); + return this; + } + + @Override + public boolean isAutoExpand() { + return buf.isAutoExpand(); + } + + @Override + public IoBuffer setAutoExpand(boolean autoExpand) { + buf.setAutoExpand(autoExpand); + return this; + } + + @Override + public IoBuffer expand(int pos, int expectedRemaining) { + buf.expand(pos, expectedRemaining); + return this; + } + + @Override + public IoBuffer expand(int expectedRemaining) { + buf.expand(expectedRemaining); + return this; + } + + @Override + public Object getObject() throws ClassNotFoundException { + return buf.getObject(); + } + + @Override + public Object getObject(ClassLoader classLoader) + throws ClassNotFoundException { + return buf.getObject(classLoader); + } + + @Override + public IoBuffer putObject(Object o) { + buf.putObject(o); + return this; + } + + @Override + public InputStream asInputStream() { + return buf.asInputStream(); + } + + @Override + public OutputStream asOutputStream() { + return buf.asOutputStream(); + } + + @Override + public IoBuffer duplicate() { + return buf.duplicate(); + } + + @Override + public IoBuffer slice() { + return buf.slice(); + } + + @Override + public IoBuffer asReadOnlyBuffer() { + return buf.asReadOnlyBuffer(); + } + + @Override + public byte[] array() { + return buf.array(); + } + + @Override + public int arrayOffset() { + return buf.arrayOffset(); + } + + @Override + public int minimumCapacity() { + return buf.minimumCapacity(); + } + + @Override + public IoBuffer minimumCapacity(int minimumCapacity) { + buf.minimumCapacity(minimumCapacity); + return this; + } + + @Override + public IoBuffer capacity(int newCapacity) { + buf.capacity(newCapacity); + return this; + } + + @Override + public boolean isReadOnly() { + return buf.isReadOnly(); + } + + @Override + public int markValue() { + return buf.markValue(); + } + + @Override + public boolean hasArray() { + return buf.hasArray(); + } + + @Override + public void free() { + buf.free(); + } + + @Override + public boolean isDerived() { + return buf.isDerived(); + } + + @Override + public boolean isAutoShrink() { + return buf.isAutoShrink(); + } + + @Override + public IoBuffer setAutoShrink(boolean autoShrink) { + buf.setAutoShrink(autoShrink); + return this; + } + + @Override + public IoBuffer shrink() { + buf.shrink(); + return this; + } + + @Override + public int getMediumInt() { + return buf.getMediumInt(); + } + + @Override + public int getUnsignedMediumInt() { + return buf.getUnsignedMediumInt(); + } + + @Override + public int getMediumInt(int index) { + return buf.getMediumInt(index); + } + + @Override + public int getUnsignedMediumInt(int index) { + return buf.getUnsignedMediumInt(index); + } + + @Override + public IoBuffer putMediumInt(int value) { + buf.putMediumInt(value); + return this; + } + + @Override + public IoBuffer putMediumInt(int index, int value) { + buf.putMediumInt(index, value); + return this; + } + + @Override + public String getHexDump(int lengthLimit) { + return buf.getHexDump(lengthLimit); + } + + @Override + public boolean prefixedDataAvailable(int prefixLength) { + return buf.prefixedDataAvailable(prefixLength); + } + + @Override + public boolean prefixedDataAvailable(int prefixLength, int maxDataLength) { + return buf.prefixedDataAvailable(prefixLength, maxDataLength); + } + + @Override + public int indexOf(byte b) { + return buf.indexOf(b); + } + + @Override + public > E getEnum(Class enumClass) { + return buf.getEnum(enumClass); + } + + @Override + public > E getEnum(int index, Class enumClass) { + return buf.getEnum(index, enumClass); + } + + @Override + public > E getEnumShort(Class enumClass) { + return buf.getEnumShort(enumClass); + } + + @Override + public > E getEnumShort(int index, Class enumClass) { + return buf.getEnumShort(index, enumClass); + } + + @Override + public > E getEnumInt(Class enumClass) { + return buf.getEnumInt(enumClass); + } + + @Override + public > E getEnumInt(int index, Class enumClass) { + return buf.getEnumInt(index, enumClass); + } + + @Override + public IoBuffer putEnum(Enum e) { + buf.putEnum(e); + return this; + } + + @Override + public IoBuffer putEnum(int index, Enum e) { + buf.putEnum(index, e); + return this; + } + + @Override + public IoBuffer putEnumShort(Enum e) { + buf.putEnumShort(e); + return this; + } + + @Override + public IoBuffer putEnumShort(int index, Enum e) { + buf.putEnumShort(index, e); + return this; + } + + @Override + public IoBuffer putEnumInt(Enum e) { + buf.putEnumInt(e); + return this; + } + + @Override + public IoBuffer putEnumInt(int index, Enum e) { + buf.putEnumInt(index, e); + return this; + } + + @Override + public > EnumSet getEnumSet(Class enumClass) { + return buf.getEnumSet(enumClass); + } + + @Override + public > EnumSet getEnumSet(int index, + Class enumClass) { + return buf.getEnumSet(index, enumClass); + } + + @Override + public > EnumSet getEnumSetShort(Class enumClass) { + return buf.getEnumSetShort(enumClass); + } + + @Override + public > EnumSet getEnumSetShort(int index, + Class enumClass) { + return buf.getEnumSetShort(index, enumClass); + } + + @Override + public > EnumSet getEnumSetInt(Class enumClass) { + return buf.getEnumSetInt(enumClass); + } + + @Override + public > EnumSet getEnumSetInt(int index, + Class enumClass) { + return buf.getEnumSetInt(index, enumClass); + } + + @Override + public > EnumSet getEnumSetLong(Class enumClass) { + return buf.getEnumSetLong(enumClass); + } + + @Override + public > EnumSet getEnumSetLong(int index, + Class enumClass) { + return buf.getEnumSetLong(index, enumClass); + } + + @Override + public > IoBuffer putEnumSet(Set set) { + buf.putEnumSet(set); + return this; + } + + @Override + public > IoBuffer putEnumSet(int index, Set set) { + buf.putEnumSet(index, set); + return this; + } + + @Override + public > IoBuffer putEnumSetShort(Set set) { + buf.putEnumSetShort(set); + return this; + } + + @Override + public > IoBuffer putEnumSetShort(int index, Set set) { + buf.putEnumSetShort(index, set); + return this; + } + + @Override + public > IoBuffer putEnumSetInt(Set set) { + buf.putEnumSetInt(set); + return this; + } + + @Override + public > IoBuffer putEnumSetInt(int index, Set set) { + buf.putEnumSetInt(index, set); + return this; + } + + @Override + public > IoBuffer putEnumSetLong(Set set) { + buf.putEnumSetLong(set); + return this; + } + + @Override + public > IoBuffer putEnumSetLong(int index, Set set) { + buf.putEnumSetLong(index, set); + return this; + } } diff --git a/src/main/java/com/google/code/yanf4j/buffer/SimpleBufferAllocator.java b/src/main/java/com/google/code/yanf4j/buffer/SimpleBufferAllocator.java index 0b1d14e05..1ef21cc8e 100644 --- a/src/main/java/com/google/code/yanf4j/buffer/SimpleBufferAllocator.java +++ b/src/main/java/com/google/code/yanf4j/buffer/SimpleBufferAllocator.java @@ -22,7 +22,6 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; - /** * A simplistic {@link IoBufferAllocator} which simply allocates a new buffer * every time. @@ -33,98 +32,83 @@ */ public class SimpleBufferAllocator implements IoBufferAllocator { - public IoBuffer allocate(int capacity, boolean direct) { - return wrap(allocateNioBuffer(capacity, direct)); - } - - - public ByteBuffer allocateNioBuffer(int capacity, boolean direct) { - ByteBuffer nioBuffer; - if (direct) { - nioBuffer = ByteBuffer.allocateDirect(capacity); - } - else { - nioBuffer = ByteBuffer.allocate(capacity); - } - return nioBuffer; - } - - - public IoBuffer wrap(ByteBuffer nioBuffer) { - return new SimpleBuffer(nioBuffer); - } - - - public void dispose() { - } - - private class SimpleBuffer extends AbstractIoBuffer { - private ByteBuffer buf; - - - protected SimpleBuffer(ByteBuffer buf) { - super(SimpleBufferAllocator.this, buf.capacity()); - this.buf = buf; - buf.order(ByteOrder.BIG_ENDIAN); - } - - - protected SimpleBuffer(SimpleBuffer parent, ByteBuffer buf) { - super(parent); - this.buf = buf; - } - - - @Override - public ByteBuffer buf() { - return buf; - } - - - @Override - protected void buf(ByteBuffer buf) { - this.buf = buf; - } - - - @Override - protected IoBuffer duplicate0() { - return new SimpleBuffer(this, this.buf.duplicate()); - } - - - @Override - protected IoBuffer slice0() { - return new SimpleBuffer(this, this.buf.slice()); - } - - - @Override - protected IoBuffer asReadOnlyBuffer0() { - return new SimpleBuffer(this, this.buf.asReadOnlyBuffer()); - } - - - @Override - public byte[] array() { - return buf.array(); - } - - - @Override - public int arrayOffset() { - return buf.arrayOffset(); - } - - - @Override - public boolean hasArray() { - return buf.hasArray(); - } - - - @Override - public void free() { - } - } + public IoBuffer allocate(int capacity, boolean direct) { + return wrap(allocateNioBuffer(capacity, direct)); + } + + public ByteBuffer allocateNioBuffer(int capacity, boolean direct) { + ByteBuffer nioBuffer; + if (direct) { + nioBuffer = ByteBuffer.allocateDirect(capacity); + } else { + nioBuffer = ByteBuffer.allocate(capacity); + } + return nioBuffer; + } + + public IoBuffer wrap(ByteBuffer nioBuffer) { + return new SimpleBuffer(nioBuffer); + } + + public void dispose() { + } + + private class SimpleBuffer extends AbstractIoBuffer { + private ByteBuffer buf; + + protected SimpleBuffer(ByteBuffer buf) { + super(SimpleBufferAllocator.this, buf.capacity()); + this.buf = buf; + buf.order(ByteOrder.BIG_ENDIAN); + } + + protected SimpleBuffer(SimpleBuffer parent, ByteBuffer buf) { + super(parent); + this.buf = buf; + } + + @Override + public ByteBuffer buf() { + return buf; + } + + @Override + protected void buf(ByteBuffer buf) { + this.buf = buf; + } + + @Override + protected IoBuffer duplicate0() { + return new SimpleBuffer(this, this.buf.duplicate()); + } + + @Override + protected IoBuffer slice0() { + return new SimpleBuffer(this, this.buf.slice()); + } + + @Override + protected IoBuffer asReadOnlyBuffer0() { + return new SimpleBuffer(this, this.buf.asReadOnlyBuffer()); + } + + @Override + public byte[] array() { + return buf.array(); + } + + @Override + public int arrayOffset() { + return buf.arrayOffset(); + } + + @Override + public boolean hasArray() { + return buf.hasArray(); + } + + @Override + public void free() { + } + } } diff --git a/src/main/java/com/google/code/yanf4j/config/Configuration.java b/src/main/java/com/google/code/yanf4j/config/Configuration.java index f490bdebe..8eced9bd1 100644 --- a/src/main/java/com/google/code/yanf4j/config/Configuration.java +++ b/src/main/java/com/google/code/yanf4j/config/Configuration.java @@ -63,9 +63,10 @@ public class Configuration { private int readThreadCount = 1; private int selectorPoolSize = System - .getProperty(XMEMCACHED_SELECTOR_POOL_SIZE) == null ? SystemUtils - .getSystemThreadCount() : Integer.parseInt(System - .getProperty(XMEMCACHED_SELECTOR_POOL_SIZE)); + .getProperty(XMEMCACHED_SELECTOR_POOL_SIZE) == null + ? SystemUtils.getSystemThreadCount() + : Integer.parseInt( + System.getProperty(XMEMCACHED_SELECTOR_POOL_SIZE)); /** * Increasing buffer size per time @@ -181,7 +182,8 @@ public final void setReadThreadCount(int readThreadCount) { this.readThreadCount = readThreadCount; } - public void setCheckSessionTimeoutInterval(long checkSessionTimeoutInterval) { + public void setCheckSessionTimeoutInterval( + long checkSessionTimeoutInterval) { this.checkSessionTimeoutInterval = checkSessionTimeoutInterval; } diff --git a/src/main/java/com/google/code/yanf4j/core/Controller.java b/src/main/java/com/google/code/yanf4j/core/Controller.java index 0e96b3e00..075b8a037 100644 --- a/src/main/java/com/google/code/yanf4j/core/Controller.java +++ b/src/main/java/com/google/code/yanf4j/core/Controller.java @@ -93,7 +93,8 @@ public abstract void setHandleReadWriteConcurrently( public int getDispatchMessageThreadCount(); - public void setDispatchMessageThreadCount(int dispatchMessageThreadPoolSize); + public void setDispatchMessageThreadCount( + int dispatchMessageThreadPoolSize); public int getWriteThreadCount(); diff --git a/src/main/java/com/google/code/yanf4j/core/impl/AbstractController.java b/src/main/java/com/google/code/yanf4j/core/impl/AbstractController.java index 49b911ade..2109c1773 100644 --- a/src/main/java/com/google/code/yanf4j/core/impl/AbstractController.java +++ b/src/main/java/com/google/code/yanf4j/core/impl/AbstractController.java @@ -62,8 +62,10 @@ * @author dennis * */ -public abstract class AbstractController implements Controller, - ControllerLifeCycle { +public abstract class AbstractController + implements + Controller, + ControllerLifeCycle { protected Statistics statistics = new DefaultStatistics(); protected long statisticsInterval; @@ -212,17 +214,17 @@ public AbstractController(Configuration configuration, Handler handler, init(configuration, handler, codecFactory); } - private synchronized void init(Configuration configuration, - Handler handler, CodecFactory codecFactory) { + private synchronized void init(Configuration configuration, Handler handler, + CodecFactory codecFactory) { setHandler(handler); setCodecFactory(codecFactory); setConfiguration(configuration); setReadThreadCount(configuration.getReadThreadCount()); setWriteThreadCount(configuration.getWriteThreadCount()); - setDispatchMessageThreadCount(configuration - .getDispatchMessageThreadCount()); - setHandleReadWriteConcurrently(configuration - .isHandleReadWriteConcurrently()); + setDispatchMessageThreadCount( + configuration.getDispatchMessageThreadCount()); + setHandleReadWriteConcurrently( + configuration.isHandleReadWriteConcurrently()); setSoTimeout(configuration.getSoTimeout()); setStatisticsConfig(configuration); setReceiveThroughputLimit(-0.1d); @@ -346,17 +348,16 @@ public synchronized void start() throws IOException { } setStarted(true); setReadEventDispatcher(DispatcherFactory.newDispatcher( - getReadThreadCount(), - new ThreadPoolExecutor.CallerRunsPolicy(), + getReadThreadCount(), new ThreadPoolExecutor.CallerRunsPolicy(), "xmemcached-read-thread")); - setWriteEventDispatcher(DispatcherFactory.newDispatcher( - getWriteThreadCount(), - new ThreadPoolExecutor.CallerRunsPolicy(), - "xmemcached-write-thread")); - setDispatchMessageDispatcher(DispatcherFactory.newDispatcher( - getDispatchMessageThreadCount(), - new ThreadPoolExecutor.CallerRunsPolicy(), - "xmemcached-dispatch-thread")); + setWriteEventDispatcher( + DispatcherFactory.newDispatcher(getWriteThreadCount(), + new ThreadPoolExecutor.CallerRunsPolicy(), + "xmemcached-write-thread")); + setDispatchMessageDispatcher( + DispatcherFactory.newDispatcher(getDispatchMessageThreadCount(), + new ThreadPoolExecutor.CallerRunsPolicy(), + "xmemcached-dispatch-thread")); startStatistics(); start0(); notifyStarted(); @@ -448,8 +449,8 @@ public final synchronized void unregisterSession(Session session) { } public void checkStatisticsForRestart() { - if (statisticsInterval > 0 - && System.currentTimeMillis() - statistics.getStartedTime() > statisticsInterval * 1000) { + if (statisticsInterval > 0 && System.currentTimeMillis() + - statistics.getStartedTime() > statisticsInterval * 1000) { statistics.restart(); } } @@ -486,8 +487,6 @@ public void stop() throws IOException { log.info("Controller has been stopped."); } - - protected abstract void stop0() throws IOException; private final void stopDispatcher() { @@ -541,8 +540,8 @@ public void setSocketOption(SocketOption socketOption, T value) { } if (!socketOption.type().equals(value.getClass())) { throw new IllegalArgumentException("Expected " - + socketOption.type().getSimpleName() - + " value,but givend " + value.getClass().getSimpleName()); + + socketOption.type().getSimpleName() + " value,but givend " + + value.getClass().getSimpleName()); } socketOptions.put(socketOption, value); } diff --git a/src/main/java/com/google/code/yanf4j/core/impl/AbstractSession.java b/src/main/java/com/google/code/yanf4j/core/impl/AbstractSession.java index 55125e343..1b4ca4853 100644 --- a/src/main/java/com/google/code/yanf4j/core/impl/AbstractSession.java +++ b/src/main/java/com/google/code/yanf4j/core/impl/AbstractSession.java @@ -250,8 +250,8 @@ public void run() { } onMessage(message, AbstractSession.this); if (start != -1) { - statistics.statisticsProcess(System.currentTimeMillis() - - start); + statistics.statisticsProcess( + System.currentTimeMillis() - start); } } @@ -347,7 +347,8 @@ protected void onStarted() { protected ReentrantLock writeLock = new ReentrantLock(); - protected AtomicReference currentMessage = new LinkedTransferQueue.PaddedAtomicReference(null); + protected AtomicReference currentMessage = new LinkedTransferQueue.PaddedAtomicReference( + null); static final class FailFuture implements Future { @@ -386,7 +387,6 @@ public void write(Object packet) { public abstract void writeFromUserCode(WriteMessage message); - public final boolean isLoopbackConnection() { return loopback; } @@ -417,8 +417,8 @@ public boolean isExpired() { public boolean isIdle() { long lastOpTimestamp = getLastOperationTimeStamp(); - return lastOpTimestamp > 0 - && System.currentTimeMillis() - lastOpTimestamp > sessionIdleTimeout; + return lastOpTimestamp > 0 && System.currentTimeMillis() + - lastOpTimestamp > sessionIdleTimeout; } public AbstractSession(SessionConfig sessionConfig) { diff --git a/src/main/java/com/google/code/yanf4j/core/impl/FutureImpl.java b/src/main/java/com/google/code/yanf4j/core/impl/FutureImpl.java index 7d4ac9bc7..55cb9f01b 100644 --- a/src/main/java/com/google/code/yanf4j/core/impl/FutureImpl.java +++ b/src/main/java/com/google/code/yanf4j/core/impl/FutureImpl.java @@ -132,8 +132,8 @@ public R get() throws InterruptedException, ExecutionException { /** * {@inheritDoc} */ - public R get(long timeout, TimeUnit unit) throws InterruptedException, - ExecutionException, TimeoutException { + public R get(long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { long startTime = System.currentTimeMillis(); long timeoutMillis = TimeUnit.MILLISECONDS.convert(timeout, unit); synchronized (this.sync) { @@ -146,7 +146,8 @@ public R get(long timeout, TimeUnit unit) throws InterruptedException, } else if (this.result != null) { return this.result; } - } else if (System.currentTimeMillis() - startTime > timeoutMillis) { + } else if (System.currentTimeMillis() + - startTime > timeoutMillis) { throw new TimeoutException(); } diff --git a/src/main/java/com/google/code/yanf4j/core/impl/FutureLockImpl.java b/src/main/java/com/google/code/yanf4j/core/impl/FutureLockImpl.java index 0ff695cb8..23b0fa683 100644 --- a/src/main/java/com/google/code/yanf4j/core/impl/FutureLockImpl.java +++ b/src/main/java/com/google/code/yanf4j/core/impl/FutureLockImpl.java @@ -46,7 +46,6 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.locks.ReentrantLock; - /** * Simple {@link Future} implementation, which uses {@link ReentrantLock} to * synchronize during the lifecycle. @@ -58,180 +57,159 @@ */ public class FutureLockImpl implements Future { - private final ReentrantLock lock; - - private boolean isDone; - - private CountDownLatch latch; - - private boolean isCancelled; - private Throwable failure; - - protected R result; - - - public FutureLockImpl() { - this(new ReentrantLock()); - } - - - public FutureLockImpl(ReentrantLock lock) { - this.lock = lock; - latch = new CountDownLatch(1); - } - - - /** - * Get current result value without any blocking. - * - * @return current result value without any blocking. - */ - public R getResult() { - try { - lock.lock(); - return result; - } - finally { - lock.unlock(); - } - } - - - /** - * Set the result value and notify about operation completion. - * - * @param result - * the result value - */ - public void setResult(R result) { - try { - lock.lock(); - this.result = result; - notifyHaveResult(); - } - finally { - lock.unlock(); - } - } - - - /** - * {@inheritDoc} - */ - public boolean cancel(boolean mayInterruptIfRunning) { - try { - lock.lock(); - isCancelled = true; - notifyHaveResult(); - return true; - } - finally { - lock.unlock(); - } - } - - - /** - * {@inheritDoc} - */ - public boolean isCancelled() { - try { - lock.lock(); - return isCancelled; - } - finally { - lock.unlock(); - } - } - - - /** - * {@inheritDoc} - */ - public boolean isDone() { - try { - lock.lock(); - return isDone; - } - finally { - lock.unlock(); - } - } - - - /** - * {@inheritDoc} - */ - public R get() throws InterruptedException, ExecutionException { - latch.await(); - - try { - lock.lock(); - if (isCancelled) { - throw new CancellationException(); - } - else if (failure != null) { - throw new ExecutionException(failure); - } - - return result; - } - finally { - lock.unlock(); - } - } - - - /** - * {@inheritDoc} - */ - public R get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { - boolean isTimeOut = !latch.await(timeout, unit); - try { - lock.lock(); - if (!isTimeOut) { - if (isCancelled) { - throw new CancellationException(); - } - else if (failure != null) { - throw new ExecutionException(failure); - } - - return result; - } - else { - throw new TimeoutException(); - } - } - finally { - lock.unlock(); - } - } - - - /** - * Notify about the failure, occured during asynchronous operation - * execution. - * - * @param failure - */ - public void failure(Throwable failure) { - try { - lock.lock(); - this.failure = failure; - notifyHaveResult(); - } - finally { - lock.unlock(); - } - } - - - /** - * Notify blocked listeners threads about operation completion. - */ - protected void notifyHaveResult() { - isDone = true; - latch.countDown(); - } + private final ReentrantLock lock; + + private boolean isDone; + + private CountDownLatch latch; + + private boolean isCancelled; + private Throwable failure; + + protected R result; + + public FutureLockImpl() { + this(new ReentrantLock()); + } + + public FutureLockImpl(ReentrantLock lock) { + this.lock = lock; + latch = new CountDownLatch(1); + } + + /** + * Get current result value without any blocking. + * + * @return current result value without any blocking. + */ + public R getResult() { + try { + lock.lock(); + return result; + } finally { + lock.unlock(); + } + } + + /** + * Set the result value and notify about operation completion. + * + * @param result + * the result value + */ + public void setResult(R result) { + try { + lock.lock(); + this.result = result; + notifyHaveResult(); + } finally { + lock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + public boolean cancel(boolean mayInterruptIfRunning) { + try { + lock.lock(); + isCancelled = true; + notifyHaveResult(); + return true; + } finally { + lock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + public boolean isCancelled() { + try { + lock.lock(); + return isCancelled; + } finally { + lock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + public boolean isDone() { + try { + lock.lock(); + return isDone; + } finally { + lock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + public R get() throws InterruptedException, ExecutionException { + latch.await(); + + try { + lock.lock(); + if (isCancelled) { + throw new CancellationException(); + } else if (failure != null) { + throw new ExecutionException(failure); + } + + return result; + } finally { + lock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + public R get(long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + boolean isTimeOut = !latch.await(timeout, unit); + try { + lock.lock(); + if (!isTimeOut) { + if (isCancelled) { + throw new CancellationException(); + } else if (failure != null) { + throw new ExecutionException(failure); + } + + return result; + } else { + throw new TimeoutException(); + } + } finally { + lock.unlock(); + } + } + + /** + * Notify about the failure, occured during asynchronous operation + * execution. + * + * @param failure + */ + public void failure(Throwable failure) { + try { + lock.lock(); + this.failure = failure; + notifyHaveResult(); + } finally { + lock.unlock(); + } + } + + /** + * Notify blocked listeners threads about operation completion. + */ + protected void notifyHaveResult() { + isDone = true; + latch.countDown(); + } } diff --git a/src/main/java/com/google/code/yanf4j/core/impl/PoolDispatcher.java b/src/main/java/com/google/code/yanf4j/core/impl/PoolDispatcher.java index 9224f4d59..5deb5e8cf 100644 --- a/src/main/java/com/google/code/yanf4j/core/impl/PoolDispatcher.java +++ b/src/main/java/com/google/code/yanf4j/core/impl/PoolDispatcher.java @@ -45,19 +45,25 @@ public class PoolDispatcher implements Dispatcher { private ThreadPoolExecutor threadPool; public PoolDispatcher(int poolSize) { - this(poolSize, 60, TimeUnit.SECONDS, new ThreadPoolExecutor.AbortPolicy(), "pool-dispatcher"); + this(poolSize, 60, TimeUnit.SECONDS, + new ThreadPoolExecutor.AbortPolicy(), "pool-dispatcher"); } public PoolDispatcher(int poolSize, long keepAliveTime, TimeUnit unit, RejectedExecutionHandler rejectedExecutionHandler, String prefix) { - this(poolSize, DEFAULT_POOL_QUEUE_SIZE_FACTOR, DEFAULT_MAX_POOL_SIZE_FACTOR, keepAliveTime, unit, + this(poolSize, DEFAULT_POOL_QUEUE_SIZE_FACTOR, + DEFAULT_MAX_POOL_SIZE_FACTOR, keepAliveTime, unit, rejectedExecutionHandler, prefix); } - public PoolDispatcher(int poolSize, int poolQueueSizeFactor, float maxPoolSizeFactor, long keepAliveTime, - TimeUnit unit, RejectedExecutionHandler rejectedExecutionHandler, String prefix) { - this.threadPool = new ThreadPoolExecutor(poolSize, (int) (maxPoolSizeFactor * poolSize), keepAliveTime, unit, - new ArrayBlockingQueue(poolSize * poolQueueSizeFactor), new WorkerThreadFactory(prefix)); + public PoolDispatcher(int poolSize, int poolQueueSizeFactor, + float maxPoolSizeFactor, long keepAliveTime, TimeUnit unit, + RejectedExecutionHandler rejectedExecutionHandler, String prefix) { + this.threadPool = new ThreadPoolExecutor(poolSize, + (int) (maxPoolSizeFactor * poolSize), keepAliveTime, unit, + new ArrayBlockingQueue( + poolSize * poolQueueSizeFactor), + new WorkerThreadFactory(prefix)); this.threadPool.setRejectedExecutionHandler(rejectedExecutionHandler); } diff --git a/src/main/java/com/google/code/yanf4j/core/impl/TextLineCodecFactory.java b/src/main/java/com/google/code/yanf4j/core/impl/TextLineCodecFactory.java index a40580717..3a23f2d31 100644 --- a/src/main/java/com/google/code/yanf4j/core/impl/TextLineCodecFactory.java +++ b/src/main/java/com/google/code/yanf4j/core/impl/TextLineCodecFactory.java @@ -106,21 +106,21 @@ public Encoder getEncoder() { return this.encoder; } -// public static void main(String args[]) { -// TextLineCodecFactory codecFactory = new TextLineCodecFactory(); -// Encoder encoder = codecFactory.getEncoder(); -// long sum = 0; -// for (int i = 0; i < 100000; i++) { -// sum += encoder.encode("hello", null).remaining(); -// } -// -// long start = System.currentTimeMillis(); -// -// for (int i = 0; i < 10000000; i++) { -// sum += encoder.encode("hello", null).remaining(); -// } -// long cost = System.currentTimeMillis() - start; -// System.out.println("sum=" + sum + ",cost = " + cost + " ms."); -// } + // public static void main(String args[]) { + // TextLineCodecFactory codecFactory = new TextLineCodecFactory(); + // Encoder encoder = codecFactory.getEncoder(); + // long sum = 0; + // for (int i = 0; i < 100000; i++) { + // sum += encoder.encode("hello", null).remaining(); + // } + // + // long start = System.currentTimeMillis(); + // + // for (int i = 0; i < 10000000; i++) { + // sum += encoder.encode("hello", null).remaining(); + // } + // long cost = System.currentTimeMillis() - start; + // System.out.println("sum=" + sum + ",cost = " + cost + " ms."); + // } } diff --git a/src/main/java/com/google/code/yanf4j/nio/TCPController.java b/src/main/java/com/google/code/yanf4j/nio/TCPController.java index f5a16fcd4..1a9b28370 100644 --- a/src/main/java/com/google/code/yanf4j/nio/TCPController.java +++ b/src/main/java/com/google/code/yanf4j/nio/TCPController.java @@ -33,8 +33,7 @@ * * @author dennis */ -public class TCPController extends SocketChannelController - { +public class TCPController extends SocketChannelController { private ServerSocketChannel serverSocketChannel; @@ -66,7 +65,8 @@ public TCPController(Configuration configuration) { } - public TCPController(Configuration configuration, CodecFactory codecFactory) { + public TCPController(Configuration configuration, + CodecFactory codecFactory) { super(configuration, null, codecFactory); } @@ -96,15 +96,15 @@ protected void doStart() throws IOException { this.serverSocketChannel.configureBlocking(false); if (this.socketOptions.get(StandardSocketOption.SO_REUSEADDR) != null) { - this.serverSocketChannel.socket().setReuseAddress( - StandardSocketOption.SO_REUSEADDR.type().cast( - this.socketOptions + this.serverSocketChannel.socket() + .setReuseAddress(StandardSocketOption.SO_REUSEADDR.type() + .cast(this.socketOptions .get(StandardSocketOption.SO_REUSEADDR))); } if (this.socketOptions.get(StandardSocketOption.SO_RCVBUF) != null) { - this.serverSocketChannel.socket().setReceiveBufferSize( - StandardSocketOption.SO_RCVBUF.type().cast( - this.socketOptions + this.serverSocketChannel.socket() + .setReceiveBufferSize(StandardSocketOption.SO_RCVBUF.type() + .cast(this.socketOptions .get(StandardSocketOption.SO_RCVBUF))); } @@ -112,8 +112,8 @@ protected void doStart() throws IOException { this.serverSocketChannel.socket().bind(this.localSocketAddress, this.backlog); } else { - this.serverSocketChannel.socket().bind( - new InetSocketAddress("localhost", 0), this.backlog); + this.serverSocketChannel.socket() + .bind(new InetSocketAddress("localhost", 0), this.backlog); } setLocalSocketAddress((InetSocketAddress) this.serverSocketChannel .socket().getLocalSocketAddress()); diff --git a/src/main/java/com/google/code/yanf4j/nio/impl/NioController.java b/src/main/java/com/google/code/yanf4j/nio/impl/NioController.java index c9a771ec5..9a052625f 100644 --- a/src/main/java/com/google/code/yanf4j/nio/impl/NioController.java +++ b/src/main/java/com/google/code/yanf4j/nio/impl/NioController.java @@ -33,8 +33,9 @@ * @author dennis * */ -public abstract class NioController extends AbstractController implements - SelectionKeyHandler { +public abstract class NioController extends AbstractController + implements + SelectionKeyHandler { protected SelectorManager selectorManager; @@ -62,7 +63,8 @@ public NioController() { super(); } - public NioController(Configuration configuration, CodecFactory codecFactory) { + public NioController(Configuration configuration, + CodecFactory codecFactory) { super(configuration, codecFactory); } @@ -136,8 +138,8 @@ protected void start0() throws IOException { */ protected void initialSelectorManager() throws IOException { if (this.selectorManager == null) { - this.selectorManager = new SelectorManager(this.selectorPoolSize, this, - this.configuration); + this.selectorManager = new SelectorManager(this.selectorPoolSize, + this, this.configuration); this.selectorManager.start(); } } @@ -209,8 +211,8 @@ protected void stop0() throws IOException { public synchronized void bind(int port) throws IOException { if (isStarted()) { - throw new IllegalStateException("Server has been bind to " - + getLocalSocketAddress()); + throw new IllegalStateException( + "Server has been bind to " + getLocalSocketAddress()); } bind(new InetSocketAddress(port)); } @@ -227,8 +229,8 @@ protected final NioSessionConfig buildSessionConfig(SelectableChannel sc, final NioSessionConfig sessionConfig = new NioSessionConfig(sc, getHandler(), this.selectorManager, getCodecFactory(), getStatistics(), queue, this.dispatchMessageDispatcher, - isHandleReadWriteConcurrently(), this.sessionTimeout, this.configuration - .getSessionIdleTimeout()); + isHandleReadWriteConcurrently(), this.sessionTimeout, + this.configuration.getSessionIdleTimeout()); return sessionConfig; } diff --git a/src/main/java/com/google/code/yanf4j/nio/impl/NioTCPSession.java b/src/main/java/com/google/code/yanf4j/nio/impl/NioTCPSession.java index f037a36f3..55398e647 100644 --- a/src/main/java/com/google/code/yanf4j/nio/impl/NioTCPSession.java +++ b/src/main/java/com/google/code/yanf4j/nio/impl/NioTCPSession.java @@ -48,11 +48,14 @@ public final boolean isExpired() { + ",this.timestamp=" + this.lastOperationTimeStamp.get() + ",current=" + System.currentTimeMillis()); } - return this.sessionTimeout <= 0 ? false : System.currentTimeMillis() - - this.lastOperationTimeStamp.get() >= this.sessionTimeout; + return this.sessionTimeout <= 0 + ? false + : System.currentTimeMillis() - this.lastOperationTimeStamp + .get() >= this.sessionTimeout; } - public NioTCPSession(NioSessionConfig sessionConfig, int readRecvBufferSize) { + public NioTCPSession(NioSessionConfig sessionConfig, + int readRecvBufferSize) { super(sessionConfig); if (this.selectableChannel != null && this.getRemoteSocketAddress() != null) { @@ -122,8 +125,8 @@ public InetSocketAddress getRemoteSocketAddress() { * @throws ClosedChannelException */ protected final Object blockingWrite(SelectableChannel channel, - WriteMessage message, IoBuffer writeBuffer) throws IOException, - ClosedChannelException { + WriteMessage message, IoBuffer writeBuffer) + throws IOException, ClosedChannelException { SelectionKey tmpKey = null; Selector writeSelector = null; int attempts = 0; @@ -153,7 +156,8 @@ protected final Object blockingWrite(SelectableChannel channel, } } } - if (!writeBuffer.hasRemaining() && message.getWriteFuture() != null) { + if (!writeBuffer.hasRemaining() + && message.getWriteFuture() != null) { message.getWriteFuture().setResult(Boolean.TRUE); } } finally { @@ -172,12 +176,13 @@ protected final Object blockingWrite(SelectableChannel channel, } @Override - protected WriteMessage wrapMessage(Object msg, Future writeFuture) { + protected WriteMessage wrapMessage(Object msg, + Future writeFuture) { WriteMessage message = new WriteMessageImpl(msg, (FutureImpl) writeFuture); if (message.getWriteBuffer() == null) { - message.setWriteBuffer(this.encoder.encode(message.getMessage(), - this)); + message.setWriteBuffer( + this.encoder.encode(message.getMessage(), this)); } return message; } @@ -185,7 +190,8 @@ protected WriteMessage wrapMessage(Object msg, Future writeFuture) { @Override protected void readFromBuffer() { if (!this.readBuffer.hasRemaining()) { - if (this.readBuffer.capacity() < Configuration.MAX_READ_BUFFER_SIZE) { + if (this.readBuffer + .capacity() < Configuration.MAX_READ_BUFFER_SIZE) { this.readBuffer = IoBuffer.wrap(ByteBufferUtils .increaseBufferCapatity(this.readBuffer.buf())); } else { @@ -207,7 +213,8 @@ protected void readFromBuffer() { decodeAndDispatch(); } else if (readCount == 0 && !((SocketChannel) this.selectableChannel).socket() - .isInputShutdown() && this.useBlockingRead) { + .isInputShutdown() + && this.useBlockingRead) { n = this.blockingRead(); if (n > 0) { readCount += n; @@ -245,8 +252,8 @@ private void decodeAndDispatch() { * @throws ClosedChannelException * @throws IOException */ - protected final int blockingRead() throws ClosedChannelException, - IOException { + protected final int blockingRead() + throws ClosedChannelException, IOException { int n = 0; int readCount = 0; Selector readSelector = SelectorFactory.getSelector(); @@ -256,7 +263,8 @@ protected final int blockingRead() throws ClosedChannelException, tmpKey = this.selectableChannel.register(readSelector, 0); tmpKey.interestOps(tmpKey.interestOps() | SelectionKey.OP_READ); int code = readSelector.select(500); - tmpKey.interestOps(tmpKey.interestOps() & ~SelectionKey.OP_READ); + tmpKey.interestOps( + tmpKey.interestOps() & ~SelectionKey.OP_READ); if (code > 0) { do { n = ((ReadableByteChannel) this.selectableChannel) @@ -299,8 +307,8 @@ public void decode() { break; } else { if (this.statistics.isStatistics()) { - this.statistics.statisticsRead(size - - this.readBuffer.remaining()); + this.statistics.statisticsRead( + size - this.readBuffer.remaining()); size = this.readBuffer.remaining(); } } diff --git a/src/main/java/com/google/code/yanf4j/nio/impl/SelectorManager.java b/src/main/java/com/google/code/yanf4j/nio/impl/SelectorManager.java index e15749722..9dffddc03 100644 --- a/src/main/java/com/google/code/yanf4j/nio/impl/SelectorManager.java +++ b/src/main/java/com/google/code/yanf4j/nio/impl/SelectorManager.java @@ -64,8 +64,8 @@ Reactor getReactorFromSession(Session session) { if (reactor == null) { reactor = nextReactor(); - final Reactor oldReactor = (Reactor) session.setAttributeIfAbsent( - REACTOR_ATTRIBUTE, reactor); + final Reactor oldReactor = (Reactor) session + .setAttributeIfAbsent(REACTOR_ATTRIBUTE, reactor); if (oldReactor != null) { reactor = oldReactor; } @@ -162,8 +162,8 @@ public final void registerSession(Session session, EventType event) { if (reactor == null) { reactor = nextReactor(); - final Reactor oldReactor = (Reactor) session.setAttributeIfAbsent( - REACTOR_ATTRIBUTE, reactor); + final Reactor oldReactor = (Reactor) session + .setAttributeIfAbsent(REACTOR_ATTRIBUTE, reactor); if (oldReactor != null) { reactor = oldReactor; } diff --git a/src/main/java/com/google/code/yanf4j/nio/impl/SocketChannelController.java b/src/main/java/com/google/code/yanf4j/nio/impl/SocketChannelController.java index b0790a18d..16f0cf12d 100644 --- a/src/main/java/com/google/code/yanf4j/nio/impl/SocketChannelController.java +++ b/src/main/java/com/google/code/yanf4j/nio/impl/SocketChannelController.java @@ -44,8 +44,8 @@ public SocketChannelController(Configuration configuration, super(configuration, null, codecFactory); } - public SocketChannelController(Configuration configuration, - Handler handler, CodecFactory codecFactory) { + public SocketChannelController(Configuration configuration, Handler handler, + CodecFactory codecFactory) { super(configuration, handler, codecFactory); } @@ -55,8 +55,8 @@ protected final void dispatchReadEvent(SelectionKey key) { if (session != null) { ((NioSession) session).onEvent(EventType.READABLE, key.selector()); } else { - log - .warn("Could not find session for readable event,maybe it is closed"); + log.warn( + "Could not find session for readable event,maybe it is closed"); } } @@ -66,8 +66,8 @@ protected final void dispatchWriteEvent(SelectionKey key) { if (session != null) { ((NioSession) session).onEvent(EventType.WRITEABLE, key.selector()); } else { - log - .warn("Could not find session for writable event,maybe it is closed"); + log.warn( + "Could not find session for writable event,maybe it is closed"); } } @@ -91,41 +91,40 @@ protected final void configureSocketChannel(SocketChannel sc) sc.socket().setSoTimeout(this.soTimeout); sc.configureBlocking(false); if (this.socketOptions.get(StandardSocketOption.SO_REUSEADDR) != null) { - sc.socket().setReuseAddress( - StandardSocketOption.SO_REUSEADDR.type().cast( - this.socketOptions + sc.socket() + .setReuseAddress(StandardSocketOption.SO_REUSEADDR.type() + .cast(this.socketOptions .get(StandardSocketOption.SO_REUSEADDR))); } if (this.socketOptions.get(StandardSocketOption.SO_SNDBUF) != null) { - sc.socket().setSendBufferSize( - StandardSocketOption.SO_SNDBUF.type().cast( - this.socketOptions + sc.socket() + .setSendBufferSize(StandardSocketOption.SO_SNDBUF.type() + .cast(this.socketOptions .get(StandardSocketOption.SO_SNDBUF))); } if (this.socketOptions.get(StandardSocketOption.SO_KEEPALIVE) != null) { - sc.socket().setKeepAlive( - StandardSocketOption.SO_KEEPALIVE.type().cast( - this.socketOptions + sc.socket() + .setKeepAlive(StandardSocketOption.SO_KEEPALIVE.type() + .cast(this.socketOptions .get(StandardSocketOption.SO_KEEPALIVE))); } if (this.socketOptions.get(StandardSocketOption.SO_LINGER) != null) { - sc.socket().setSoLinger( - this.soLingerOn, - StandardSocketOption.SO_LINGER.type().cast( - this.socketOptions + sc.socket().setSoLinger(this.soLingerOn, + StandardSocketOption.SO_LINGER.type() + .cast(this.socketOptions .get(StandardSocketOption.SO_LINGER))); } if (this.socketOptions.get(StandardSocketOption.SO_RCVBUF) != null) { - sc.socket().setReceiveBufferSize( - StandardSocketOption.SO_RCVBUF.type().cast( - this.socketOptions + sc.socket() + .setReceiveBufferSize(StandardSocketOption.SO_RCVBUF.type() + .cast(this.socketOptions .get(StandardSocketOption.SO_RCVBUF))); } if (this.socketOptions.get(StandardSocketOption.TCP_NODELAY) != null) { - sc.socket().setTcpNoDelay( - StandardSocketOption.TCP_NODELAY.type().cast( - this.socketOptions + sc.socket() + .setTcpNoDelay(StandardSocketOption.TCP_NODELAY.type() + .cast(this.socketOptions .get(StandardSocketOption.TCP_NODELAY))); } } diff --git a/src/main/java/com/google/code/yanf4j/statistics/impl/SimpleStatistics.java b/src/main/java/com/google/code/yanf4j/statistics/impl/SimpleStatistics.java index dec6533c5..1f32ad67d 100644 --- a/src/main/java/com/google/code/yanf4j/statistics/impl/SimpleStatistics.java +++ b/src/main/java/com/google/code/yanf4j/statistics/impl/SimpleStatistics.java @@ -123,7 +123,8 @@ public long getStartedTime() { } public double getProcessedMessageAverageTime() { - return this.processMessageCount.get() == 0 ? 0 + return this.processMessageCount.get() == 0 + ? 0 : (double) this.processMessageTotalTime.get() / this.processMessageCount.get(); } @@ -196,50 +197,61 @@ public void statisticsWrite(long n) { } public long getRecvMessageAverageSize() { - return this.recvMessageCount.get() == 0 ? 0 : this.recvMessageTotalSize - .get() - / this.recvMessageCount.get(); + return this.recvMessageCount.get() == 0 + ? 0 + : this.recvMessageTotalSize.get() / this.recvMessageCount.get(); } public double getRecvMessageCountPerSecond() { - long duration = (this.stopTime == -1) ? (System.currentTimeMillis() - this.startTime) + long duration = (this.stopTime == -1) + ? (System.currentTimeMillis() - this.startTime) : (this.stopTime - this.startTime); - return duration == 0 ? 0 : (double) this.recvMessageCount.get() * 1000 - / duration; + return duration == 0 + ? 0 + : (double) this.recvMessageCount.get() * 1000 / duration; } public double getWriteMessageCountPerSecond() { - long duration = (this.stopTime == -1) ? (System.currentTimeMillis() - this.startTime) + long duration = (this.stopTime == -1) + ? (System.currentTimeMillis() - this.startTime) : (this.stopTime - this.startTime); - return duration == 0 ? 0 : (double) this.writeMessageCount.get() * 1000 - / duration; + return duration == 0 + ? 0 + : (double) this.writeMessageCount.get() * 1000 / duration; } public long getWriteMessageAverageSize() { - return this.writeMessageCount.get() == 0 ? 0 + return this.writeMessageCount.get() == 0 + ? 0 : this.writeMessageTotalSize.get() / this.writeMessageCount.get(); } public double getAcceptCountPerSecond() { - long duration = (this.stopTime == -1) ? (System.currentTimeMillis() - this.startTime) + long duration = (this.stopTime == -1) + ? (System.currentTimeMillis() - this.startTime) : (this.stopTime - this.startTime); - return duration == 0 ? 0 : (double) this.acceptCount.get() * 1000 - / duration; + return duration == 0 + ? 0 + : (double) this.acceptCount.get() * 1000 / duration; } public double getReceiveBytesPerSecond() { - long duration = (this.stopTime == -1) ? (System.currentTimeMillis() - this.startTime) + long duration = (this.stopTime == -1) + ? (System.currentTimeMillis() - this.startTime) : (this.stopTime - this.startTime); - return duration == 0 ? 0 : (double) this.recvMessageTotalSize.get() - * 1000 / duration; + return duration == 0 + ? 0 + : (double) this.recvMessageTotalSize.get() * 1000 / duration; } public double getSendBytesPerSecond() { - long duration = (this.stopTime == -1) ? (System.currentTimeMillis() - this.startTime) + long duration = (this.stopTime == -1) + ? (System.currentTimeMillis() - this.startTime) : (this.stopTime - this.startTime); - return duration == 0 ? 0 : (double) this.writeMessageTotalSize.get() - * 1000 / duration; + return duration == 0 + ? 0 + : (double) this.writeMessageTotalSize.get() * 1000 / duration; } public void statisticsAccept() { diff --git a/src/main/java/com/google/code/yanf4j/util/ByteBufferUtils.java b/src/main/java/com/google/code/yanf4j/util/ByteBufferUtils.java index c5891e53c..f2cda1f7b 100644 --- a/src/main/java/com/google/code/yanf4j/util/ByteBufferUtils.java +++ b/src/main/java/com/google/code/yanf4j/util/ByteBufferUtils.java @@ -44,14 +44,14 @@ import com.google.code.yanf4j.config.Configuration; - public class ByteBufferUtils { /** * * @param byteBuffer * @return * */ - public static final ByteBuffer increaseBufferCapatity(ByteBuffer byteBuffer) { + public static final ByteBuffer increaseBufferCapatity( + ByteBuffer byteBuffer) { if (byteBuffer == null) { throw new IllegalArgumentException("buffer is null"); @@ -65,8 +65,9 @@ public static final ByteBuffer increaseBufferCapatity(ByteBuffer byteBuffer) { if (capacity < 0) { throw new IllegalArgumentException("capacity can't be negative"); } - ByteBuffer result = (byteBuffer.isDirect() ? ByteBuffer - .allocateDirect(capacity) : ByteBuffer.allocate(capacity)); + ByteBuffer result = (byteBuffer.isDirect() + ? ByteBuffer.allocateDirect(capacity) + : ByteBuffer.allocate(capacity)); result.order(byteBuffer.order()); byteBuffer.flip(); result.put(byteBuffer); @@ -124,8 +125,8 @@ public static final void clear(ByteBuffer[] buffers) { } public static final String toHex(byte b) { - return ("" + "0123456789ABCDEF".charAt(0xf & b >> 4) + "0123456789ABCDEF" - .charAt(b & 0xf)); + return ("" + "0123456789ABCDEF".charAt(0xf & b >> 4) + + "0123456789ABCDEF".charAt(b & 0xf)); } public static final int indexOf(ByteBuffer buffer, ByteBuffer pattern) { diff --git a/src/main/java/com/google/code/yanf4j/util/CircularQueue.java b/src/main/java/com/google/code/yanf4j/util/CircularQueue.java index 8f328d70f..37d4b6abc 100644 --- a/src/main/java/com/google/code/yanf4j/util/CircularQueue.java +++ b/src/main/java/com/google/code/yanf4j/util/CircularQueue.java @@ -34,8 +34,11 @@ * * @param */ -public class CircularQueue extends AbstractList implements List, - Queue, Serializable { +public class CircularQueue extends AbstractList + implements + List, + Queue, + Serializable { private static final long serialVersionUID = 3993421269224511264L; @@ -195,11 +198,11 @@ private void expandIfNeeded() { Object[] tmp = new Object[newLen]; if (this.first < this.last) { - System.arraycopy(this.items, this.first, tmp, 0, this.last - - this.first); + System.arraycopy(this.items, this.first, tmp, 0, + this.last - this.first); } else { - System.arraycopy(this.items, this.first, tmp, 0, oldLen - - this.first); + System.arraycopy(this.items, this.first, tmp, 0, + oldLen - this.first); System.arraycopy(this.items, 0, tmp, oldLen - this.first, this.last); } @@ -241,11 +244,11 @@ private void shrinkIfNeeded() { // Copy only when there's something to copy. if (size > 0) { if (this.first < this.last) { - System.arraycopy(this.items, this.first, tmp, 0, this.last - - this.first); + System.arraycopy(this.items, this.first, tmp, 0, + this.last - this.first); } else { - System.arraycopy(this.items, this.first, tmp, 0, oldLen - - this.first); + System.arraycopy(this.items, this.first, tmp, 0, + oldLen - this.first); System.arraycopy(this.items, 0, tmp, oldLen - this.first, this.last); } @@ -321,8 +324,8 @@ public E remove(int idx) { // Remove a room for the removed element. if (this.first < this.last) { - System.arraycopy(this.items, this.first, this.items, - this.first + 1, realIdx - this.first); + System.arraycopy(this.items, this.first, this.items, this.first + 1, + realIdx - this.first); } else { if (realIdx >= this.first) { System.arraycopy(this.items, this.first, this.items, diff --git a/src/main/java/com/google/code/yanf4j/util/ConcurrentHashSet.java b/src/main/java/com/google/code/yanf4j/util/ConcurrentHashSet.java index 20032269f..fc300d436 100644 --- a/src/main/java/com/google/code/yanf4j/util/ConcurrentHashSet.java +++ b/src/main/java/com/google/code/yanf4j/util/ConcurrentHashSet.java @@ -31,7 +31,8 @@ * A {@link ConcurrentHashMap}-backed {@link Set}. * * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev: 597692 $, $Date: 2007-11-23 08:56:32 -0700 (Fri, 23 Nov 2007) $ + * @version $Rev: 597692 $, $Date: 2007-11-23 08:56:32 -0700 (Fri, 23 Nov 2007) + * $ */ public class ConcurrentHashSet extends MapBackedSet { diff --git a/src/main/java/com/google/code/yanf4j/util/DispatcherFactory.java b/src/main/java/com/google/code/yanf4j/util/DispatcherFactory.java index 0476829aa..26c0d2d76 100644 --- a/src/main/java/com/google/code/yanf4j/util/DispatcherFactory.java +++ b/src/main/java/com/google/code/yanf4j/util/DispatcherFactory.java @@ -12,11 +12,11 @@ * */ public class DispatcherFactory { - public static com.google.code.yanf4j.core.Dispatcher newDispatcher( - int size, RejectedExecutionHandler rejectedExecutionHandler,String prefix) { + public static com.google.code.yanf4j.core.Dispatcher newDispatcher(int size, + RejectedExecutionHandler rejectedExecutionHandler, String prefix) { if (size > 0) { return new PoolDispatcher(size, 60, TimeUnit.SECONDS, - rejectedExecutionHandler,prefix); + rejectedExecutionHandler, prefix); } else { return null; } diff --git a/src/main/java/com/google/code/yanf4j/util/LinkedTransferQueue.java b/src/main/java/com/google/code/yanf4j/util/LinkedTransferQueue.java index 8021ed625..c3725fb79 100644 --- a/src/main/java/com/google/code/yanf4j/util/LinkedTransferQueue.java +++ b/src/main/java/com/google/code/yanf4j/util/LinkedTransferQueue.java @@ -1,38 +1,38 @@ - /* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2008 Sun Microsystems, Inc. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can obtain - * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html - * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt. - * Sun designates this particular file as subject to the "Classpath" exception - * as provided by Sun in the GPL Version 2 section of the License file that - * accompanied this code. If applicable, add the following below the License - * Header, with the fields enclosed by brackets [] replaced by your own - * identifying information: "Portions Copyrighted [year] - * [name of copyright owner]" - * - * Contributor(s): - * - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ +/* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. +* +* Copyright 1997-2008 Sun Microsystems, Inc. All rights reserved. +* +* The contents of this file are subject to the terms of either the GNU +* General Public License Version 2 only ("GPL") or the Common Development +* and Distribution License("CDDL") (collectively, the "License"). You +* may not use this file except in compliance with the License. You can obtain +* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html +* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific +* language governing permissions and limitations under the License. +* +* When distributing the software, include this License Header Notice in each +* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt. +* Sun designates this particular file as subject to the "Classpath" exception +* as provided by Sun in the GPL Version 2 section of the License file that +* accompanied this code. If applicable, add the following below the License +* Header, with the fields enclosed by brackets [] replaced by your own +* identifying information: "Portions Copyrighted [year] +* [name of copyright owner]" +* +* Contributor(s): +* +* If you wish your version of this file to be governed by only the CDDL or +* only the GPL Version 2, indicate your decision by adding "[Contributor] +* elects to include this software in this distribution under the [CDDL or GPL +* Version 2] license." If you don't indicate a single choice of license, a +* recipient has the option to distribute your version of this file under +* either the CDDL, the GPL Version 2 or to extend the choice of license to +* its licensees as provided above. However, if you add GPL Version 2 code +* and therefore, elected the GPL Version 2 license, then the option applies +* only if the new code is made subject to such option by the copyright +* holder. +*/ /* * Written by Doug Lea with assistance from members of JCP JSR-166 @@ -53,771 +53,775 @@ import java.util.concurrent.locks.LockSupport; /** - * An unbounded TransferQueue based on linked nodes. - * This queue orders elements FIFO (first-in-first-out) with respect - * to any given producer. The head of the queue is that - * element that has been on the queue the longest time for some - * producer. The tail of the queue is that element that has - * been on the queue the shortest time for some producer. + * An unbounded TransferQueue based on linked nodes. This queue orders + * elements FIFO (first-in-first-out) with respect to any given producer. The + * head of the queue is that element that has been on the queue the + * longest time for some producer. The tail of the queue is that + * element that has been on the queue the shortest time for some producer. * - *

Beware that, unlike in most collections, the size - * method is NOT a constant-time operation. Because of the - * asynchronous nature of these queues, determining the current number - * of elements requires a traversal of the elements. + *

+ * Beware that, unlike in most collections, the size method is + * NOT a constant-time operation. Because of the asynchronous nature of + * these queues, determining the current number of elements requires a traversal + * of the elements. * - *

This class and its iterator implement all of the - * optional methods of the {@link Collection} and {@link - * Iterator} interfaces. + *

+ * This class and its iterator implement all of the optional methods of + * the {@link Collection} and {@link Iterator} interfaces. * - *

Memory consistency effects: As with other concurrent - * collections, actions in a thread prior to placing an object into a - * {@code LinkedTransferQueue} + *

+ * Memory consistency effects: As with other concurrent collections, actions in + * a thread prior to placing an object into a {@code LinkedTransferQueue} * happen-before - * actions subsequent to the access or removal of that element from - * the {@code LinkedTransferQueue} in another thread. + * actions subsequent to the access or removal of that element from the + * {@code LinkedTransferQueue} in another thread. * * @author Doug Lea * @author The Netty Project (netty-dev@lists.jboss.org) * @author Trustin Lee (tlee@redhat.com) * - * @param the type of elements held in this collection + * @param + * the type of elements held in this collection * */ -public class LinkedTransferQueue extends AbstractQueue implements BlockingQueue { - - /* - * This class extends the approach used in FIFO-mode - * SynchronousQueues. See the internal documentation, as well as - * the PPoPP 2006 paper "Scalable Synchronous Queues" by Scherer, - * Lea & Scott - * (http://www.cs.rice.edu/~wns1/papers/2006-PPoPP-SQ.pdf) - * - * The main extension is to provide different Wait modes for the - * main "xfer" method that puts or takes items. These don't - * impact the basic dual-queue logic, but instead control whether - * or how threads block upon insertion of request or data nodes - * into the dual queue. It also uses slightly different - * conventions for tracking whether nodes are off-list or - * cancelled. - */ - - // Wait modes for xfer method - private static final int NOWAIT = 0; - private static final int TIMEOUT = 1; - private static final int WAIT = 2; - - /** The number of CPUs, for spin control */ - private static final int NCPUS = Runtime.getRuntime().availableProcessors(); - - /** - * The number of times to spin before blocking in timed waits. - * The value is empirically derived -- it works well across a - * variety of processors and OSes. Empirically, the best value - * seems not to vary with number of CPUs (beyond 2) so is just - * a constant. - */ - private static final int maxTimedSpins = NCPUS < 2? 0 : 32; - - /** - * The number of times to spin before blocking in untimed waits. - * This is greater than timed value because untimed waits spin - * faster since they don't need to check times on each spin. - */ - private static final int maxUntimedSpins = maxTimedSpins * 16; - - /** - * The number of nanoseconds for which it is faster to spin - * rather than to use timed park. A rough estimate suffices. - */ - private static final long spinForTimeoutThreshold = 1000L; - - /** - * Node class for LinkedTransferQueue. Opportunistically - * subclasses from AtomicReference to represent item. Uses Object, - * not E, to allow setting item to "this" after use, to avoid - * garbage retention. Similarly, setting the next field to this is - * used as sentinel that node is off list. - */ - private static final class QNode extends AtomicReference { - private static final long serialVersionUID = 5925596372370723938L; - - transient volatile QNode next; - transient volatile Thread waiter; // to control park/unpark - final boolean isData; - public long p1,p2,p3,p4,p5,p6,p7; - QNode(Object item, boolean isData) { - super(item); - this.isData = isData; - } - - private static final AtomicReferenceFieldUpdater nextUpdater; - static { - AtomicReferenceFieldUpdater tmp = null; - try { - tmp = AtomicReferenceFieldUpdater.newUpdater( - QNode.class, QNode.class, "next"); - - // Test if AtomicReferenceFieldUpdater is really working. - QNode testNode = new QNode(null, false); - tmp.set(testNode, testNode); - if (testNode.next != testNode) { - // Not set as expected - fall back to the safe mode. - throw new Exception(); - } - } catch (Throwable t) { - // Running in a restricted environment with a security manager. - tmp = null; - } - nextUpdater = tmp; - } - - boolean casNext(QNode cmp, QNode val) { - if (nextUpdater != null) { - return nextUpdater.compareAndSet(this, cmp, val); - } else { - return alternativeCasNext(cmp, val); - } - } - - private synchronized boolean alternativeCasNext(QNode cmp, QNode val) { - if (this.next == cmp) { - this.next = val; - return true; - } else { - return false; - } - } - } - - /** - * Padded version of AtomicReference used for head, tail and - * cleanMe, to alleviate contention across threads CASing one vs - * the other. - */ - public static final class PaddedAtomicReference extends AtomicReference { - private static final long serialVersionUID = 4684288940772921317L; - - // enough padding for 64bytes with 4byte refs - @SuppressWarnings("unused") - public Object p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, pe; - public PaddedAtomicReference(T r) { super(r); } - } - - - /** head of the queue */ - private final PaddedAtomicReference head; - /** tail of the queue */ - private final PaddedAtomicReference tail; - - /** - * Reference to a cancelled node that might not yet have been - * unlinked from queue because it was the last inserted node - * when it cancelled. - */ - private final PaddedAtomicReference cleanMe; - - /** - * Tries to cas nh as new head; if successful, unlink - * old head's next node to avoid garbage retention. - */ - private boolean advanceHead(QNode h, QNode nh) { - if (h == this.head.get() && this.head.compareAndSet(h, nh)) { - h.next = h; // forget old next - return true; - } - return false; - } - - /** - * Puts or takes an item. Used for most queue operations (except - * poll() and tryTransfer()). See the similar code in - * SynchronousQueue for detailed explanation. - * @param e the item or if null, signifies that this is a take - * @param mode the wait mode: NOWAIT, TIMEOUT, WAIT - * @param nanos timeout in nanosecs, used only if mode is TIMEOUT - * @return an item, or null on failure - */ - private Object xfer(Object e, int mode, long nanos) { - boolean isData = e != null; - QNode s = null; - final PaddedAtomicReference head = this.head; - final PaddedAtomicReference tail = this.tail; - - for (;;) { - QNode t = tail.get(); - QNode h = head.get(); - - if (t != null && (t == h || t.isData == isData)) { - if (s == null) { - s = new QNode(e, isData); - } - QNode last = t.next; - if (last != null) { - if (t == tail.get()) { - tail.compareAndSet(t, last); - } - } - else if (t.casNext(null, s)) { - tail.compareAndSet(t, s); - return awaitFulfill(t, s, e, mode, nanos); - } - } - - else if (h != null) { - QNode first = h.next; - if (t == tail.get() && first != null && - advanceHead(h, first)) { - Object x = first.get(); - if (x != first && first.compareAndSet(x, e)) { - LockSupport.unpark(first.waiter); - return isData? e : x; - } - } - } - } - } - - - /** - * Version of xfer for poll() and tryTransfer, which - * simplifies control paths both here and in xfer - */ - private Object fulfill(Object e) { - boolean isData = e != null; - final PaddedAtomicReference head = this.head; - final PaddedAtomicReference tail = this.tail; - - for (;;) { - QNode t = tail.get(); - QNode h = head.get(); - - if (t != null && (t == h || t.isData == isData)) { - QNode last = t.next; - if (t == tail.get()) { - if (last != null) { - tail.compareAndSet(t, last); - } else { - return null; - } - } - } - else if (h != null) { - QNode first = h.next; - if (t == tail.get() && - first != null && - advanceHead(h, first)) { - Object x = first.get(); - if (x != first && first.compareAndSet(x, e)) { - LockSupport.unpark(first.waiter); - return isData? e : x; - } - } - } - } - } - - /** - * Spins/blocks until node s is fulfilled or caller gives up, - * depending on wait mode. - * - * @param pred the predecessor of waiting node - * @param s the waiting node - * @param e the comparison value for checking match - * @param mode mode - * @param nanos timeout value - * @return matched item, or s if cancelled - */ - private Object awaitFulfill(QNode pred, QNode s, Object e, - int mode, long nanos) { - if (mode == NOWAIT) { - return null; - } - - long lastTime = mode == TIMEOUT? System.nanoTime() : 0; - Thread w = Thread.currentThread(); - int spins = -1; // set to desired spin count below - for (;;) { - if (w.isInterrupted()) { - s.compareAndSet(e, s); - } - Object x = s.get(); - if (x != e) { // Node was matched or cancelled - advanceHead(pred, s); // unlink if head - if (x == s) { // was cancelled - clean(pred, s); - return null; - } - else if (x != null) { - s.set(s); // avoid garbage retention - return x; - } else { - return e; - } - } - if (mode == TIMEOUT) { - long now = System.nanoTime(); - nanos -= now - lastTime; - lastTime = now; - if (nanos <= 0) { - s.compareAndSet(e, s); // try to cancel - continue; - } - } - if (spins < 0) { - QNode h = this.head.get(); // only spin if at head - spins = h != null && h.next == s ? - (mode == TIMEOUT? - maxTimedSpins : maxUntimedSpins) : 0; - } - if (spins > 0) { - --spins; - } else if (s.waiter == null) { - s.waiter = w; - } else if (mode != TIMEOUT) { - // LockSupport.park(this); - LockSupport.park(); // allows run on java5 - s.waiter = null; - spins = -1; - } - else if (nanos > spinForTimeoutThreshold) { - // LockSupport.parkNanos(this, nanos); - LockSupport.parkNanos(nanos); - s.waiter = null; - spins = -1; - } - } - } - - /** - * Returns validated tail for use in cleaning methods - */ - private QNode getValidatedTail() { - for (;;) { - QNode h = this.head.get(); - QNode first = h.next; - if (first != null && first.next == first) { // help advance - advanceHead(h, first); - continue; - } - QNode t = this.tail.get(); - QNode last = t.next; - if (t == this.tail.get()) { - if (last != null) { - this.tail.compareAndSet(t, last); // help advance - } else { - return t; - } - } - } - } - - /** - * Gets rid of cancelled node s with original predecessor pred. - * @param pred predecessor of cancelled node - * @param s the cancelled node - */ - void clean(QNode pred, QNode s) { - Thread w = s.waiter; - if (w != null) { // Wake up thread - s.waiter = null; - if (w != Thread.currentThread()) { - LockSupport.unpark(w); - } - } - /* - * At any given time, exactly one node on list cannot be - * deleted -- the last inserted node. To accommodate this, if - * we cannot delete s, we save its predecessor as "cleanMe", - * processing the previously saved version first. At least one - * of node s or the node previously saved can always be - * processed, so this always terminates. - */ - while (pred.next == s) { - QNode oldpred = reclean(); // First, help get rid of cleanMe - QNode t = getValidatedTail(); - if (s != t) { // If not tail, try to unsplice - QNode sn = s.next; // s.next == s means s already off list - if (sn == s || pred.casNext(s, sn)) { - break; - } - } - else if (oldpred == pred || // Already saved - oldpred == null && this.cleanMe.compareAndSet(null, pred)) { - break; // Postpone cleaning - } - } - } - - /** - * Tries to unsplice the cancelled node held in cleanMe that was - * previously uncleanable because it was at tail. - * @return current cleanMe node (or null) - */ - private QNode reclean() { - /* - * cleanMe is, or at one time was, predecessor of cancelled - * node s that was the tail so could not be unspliced. If s - * is no longer the tail, try to unsplice if necessary and - * make cleanMe slot available. This differs from similar - * code in clean() because we must check that pred still - * points to a cancelled node that must be unspliced -- if - * not, we can (must) clear cleanMe without unsplicing. - * This can loop only due to contention on casNext or - * clearing cleanMe. - */ - QNode pred; - while ((pred = this.cleanMe.get()) != null) { - QNode t = getValidatedTail(); - QNode s = pred.next; - if (s != t) { - QNode sn; - if (s == null || s == pred || s.get() != s || - (sn = s.next) == s || pred.casNext(s, sn)) { - this.cleanMe.compareAndSet(pred, null); - } - } else { - break; - } - } - return pred; - } - - @SuppressWarnings("unchecked") - E cast(Object e) { - return (E)e; - } - - /** - * Creates an initially empty LinkedTransferQueue. - */ - public LinkedTransferQueue() { - QNode dummy = new QNode(null, false); - this.head = new PaddedAtomicReference(dummy); - this.tail = new PaddedAtomicReference(dummy); - this.cleanMe = new PaddedAtomicReference(null); - } - - /** - * Creates a LinkedTransferQueue - * initially containing the elements of the given collection, - * added in traversal order of the collection's iterator. - * @param c the collection of elements to initially contain - * @throws NullPointerException if the specified collection or any - * of its elements are null - */ - public LinkedTransferQueue(Collection c) { - this(); - addAll(c); - } - - public void put(E e) throws InterruptedException { - if (e == null) { - throw new NullPointerException(); - } - if (Thread.interrupted()) { - throw new InterruptedException(); - } - xfer(e, NOWAIT, 0); - } - - public boolean offer(E e, long timeout, TimeUnit unit) - throws InterruptedException { - if (e == null) { - throw new NullPointerException(); - } - if (Thread.interrupted()) { - throw new InterruptedException(); - } - xfer(e, NOWAIT, 0); - return true; - } - - public boolean offer(E e) { - if (e == null) { - throw new NullPointerException(); - } - xfer(e, NOWAIT, 0); - return true; - } - - public void transfer(E e) throws InterruptedException { - if (e == null) { - throw new NullPointerException(); - } - if (xfer(e, WAIT, 0) == null) { - Thread.interrupted(); - throw new InterruptedException(); - } - } - - public boolean tryTransfer(E e, long timeout, TimeUnit unit) - throws InterruptedException { - if (e == null) { - throw new NullPointerException(); - } - if (xfer(e, TIMEOUT, unit.toNanos(timeout)) != null) { - return true; - } - if (!Thread.interrupted()) { - return false; - } - throw new InterruptedException(); - } - - public boolean tryTransfer(E e) { - if (e == null) { - throw new NullPointerException(); - } - return fulfill(e) != null; - } - - public E take() throws InterruptedException { - Object e = xfer(null, WAIT, 0); - if (e != null) { - return cast(e); - } - Thread.interrupted(); - throw new InterruptedException(); - } - - public E poll(long timeout, TimeUnit unit) throws InterruptedException { - Object e = xfer(null, TIMEOUT, unit.toNanos(timeout)); - if (e != null || !Thread.interrupted()) { - return cast(e); - } - throw new InterruptedException(); - } - - public E poll() { - return cast(fulfill(null)); - } - - public int drainTo(Collection c) { - if (c == null) { - throw new NullPointerException(); - } - if (c == this) { - throw new IllegalArgumentException(); - } - int n = 0; - E e; - while ( (e = poll()) != null) { - c.add(e); - ++n; - } - return n; - } - - public int drainTo(Collection c, int maxElements) { - if (c == null) { - throw new NullPointerException(); - } - if (c == this) { - throw new IllegalArgumentException(); - } - int n = 0; - E e; - while (n < maxElements && (e = poll()) != null) { - c.add(e); - ++n; - } - return n; - } - - // Traversal-based methods - - /** - * Return head after performing any outstanding helping steps - */ - QNode traversalHead() { - for (;;) { - QNode t = this.tail.get(); - QNode h = this.head.get(); - if (h != null && t != null) { - QNode last = t.next; - QNode first = h.next; - if (t == this.tail.get()) { - if (last != null) { - this.tail.compareAndSet(t, last); - } else if (first != null) { - Object x = first.get(); - if (x == first) { - advanceHead(h, first); - } else { - return h; - } - } else { - return h; - } - } - } - } - } - - @Override - public Iterator iterator() { - return new Itr(); - } - - /** - * Iterators. Basic strategy is to traverse list, treating - * non-data (i.e., request) nodes as terminating list. - * Once a valid data node is found, the item is cached - * so that the next call to next() will return it even - * if subsequently removed. - */ - class Itr implements Iterator { - QNode nextNode; // Next node to return next - QNode currentNode; // last returned node, for remove() - QNode prevNode; // predecessor of last returned node - E nextItem; // Cache of next item, once commited to in next - - Itr() { - this.nextNode = traversalHead(); - advance(); - } - - E advance() { - this.prevNode = this.currentNode; - this.currentNode = this.nextNode; - E x = this.nextItem; - - QNode p = this.nextNode.next; - for (;;) { - if (p == null || !p.isData) { - this.nextNode = null; - this.nextItem = null; - return x; - } - Object item = p.get(); - if (item != p && item != null) { - this.nextNode = p; - this.nextItem = cast(item); - return x; - } - this.prevNode = p; - p = p.next; - } - } - - public boolean hasNext() { - return this.nextNode != null; - } - - public E next() { - if (this.nextNode == null) { - throw new NoSuchElementException(); - } - return advance(); - } - - public void remove() { - QNode p = this.currentNode; - QNode prev = this.prevNode; - if (prev == null || p == null) { - throw new IllegalStateException(); - } - Object x = p.get(); - if (x != null && x != p && p.compareAndSet(x, p)) { - clean(prev, p); - } - } - } - - public E peek() { - for (;;) { - QNode h = traversalHead(); - QNode p = h.next; - if (p == null) { - return null; - } - Object x = p.get(); - if (p != x) { - if (!p.isData) { - return null; - } - if (x != null) { - return cast(x); - } - } - } - } - - @Override - public boolean isEmpty() { - for (;;) { - QNode h = traversalHead(); - QNode p = h.next; - if (p == null) { - return true; - } - Object x = p.get(); - if (p != x) { - if (!p.isData) { - return true; - } - if (x != null) { - return false; - } - } - } - } - - public boolean hasWaitingConsumer() { - for (;;) { - QNode h = traversalHead(); - QNode p = h.next; - if (p == null) { - return false; - } - Object x = p.get(); - if (p != x) { - return !p.isData; - } - } - } - - /** - * Returns the number of elements in this queue. If this queue - * contains more than Integer.MAX_VALUE elements, returns - * Integer.MAX_VALUE. - * - *

Beware that, unlike in most collections, this method is - * NOT a constant-time operation. Because of the - * asynchronous nature of these queues, determining the current - * number of elements requires an O(n) traversal. - * - * @return the number of elements in this queue - */ - @Override - public int size() { - int count = 0; - QNode h = traversalHead(); - for (QNode p = h.next; p != null && p.isData; p = p.next) { - Object x = p.get(); - if (x != null && x != p) { - if (++count == Integer.MAX_VALUE) { - break; - } - } - } - return count; - } - - public int getWaitingConsumerCount() { - int count = 0; - QNode h = traversalHead(); - for (QNode p = h.next; p != null && !p.isData; p = p.next) { - if (p.get() == null) { - if (++count == Integer.MAX_VALUE) { - break; - } - } - } - return count; - } - - public int remainingCapacity() { - return Integer.MAX_VALUE; - } +public class LinkedTransferQueue extends AbstractQueue + implements + BlockingQueue { + + /* + * This class extends the approach used in FIFO-mode SynchronousQueues. See + * the internal documentation, as well as the PPoPP 2006 paper + * "Scalable Synchronous Queues" by Scherer, Lea & Scott + * (http://www.cs.rice.edu/~wns1/papers/2006-PPoPP-SQ.pdf) + * + * The main extension is to provide different Wait modes for the main "xfer" + * method that puts or takes items. These don't impact the basic dual-queue + * logic, but instead control whether or how threads block upon insertion of + * request or data nodes into the dual queue. It also uses slightly + * different conventions for tracking whether nodes are off-list or + * cancelled. + */ + + // Wait modes for xfer method + private static final int NOWAIT = 0; + private static final int TIMEOUT = 1; + private static final int WAIT = 2; + + /** The number of CPUs, for spin control */ + private static final int NCPUS = Runtime.getRuntime().availableProcessors(); + + /** + * The number of times to spin before blocking in timed waits. The value is + * empirically derived -- it works well across a variety of processors and + * OSes. Empirically, the best value seems not to vary with number of CPUs + * (beyond 2) so is just a constant. + */ + private static final int maxTimedSpins = NCPUS < 2 ? 0 : 32; + + /** + * The number of times to spin before blocking in untimed waits. This is + * greater than timed value because untimed waits spin faster since they + * don't need to check times on each spin. + */ + private static final int maxUntimedSpins = maxTimedSpins * 16; + + /** + * The number of nanoseconds for which it is faster to spin rather than to + * use timed park. A rough estimate suffices. + */ + private static final long spinForTimeoutThreshold = 1000L; + + /** + * Node class for LinkedTransferQueue. Opportunistically subclasses from + * AtomicReference to represent item. Uses Object, not E, to allow setting + * item to "this" after use, to avoid garbage retention. Similarly, setting + * the next field to this is used as sentinel that node is off list. + */ + private static final class QNode extends AtomicReference { + private static final long serialVersionUID = 5925596372370723938L; + + transient volatile QNode next; + transient volatile Thread waiter; // to control park/unpark + final boolean isData; + public long p1, p2, p3, p4, p5, p6, p7; + QNode(Object item, boolean isData) { + super(item); + this.isData = isData; + } + + private static final AtomicReferenceFieldUpdater nextUpdater; + static { + AtomicReferenceFieldUpdater tmp = null; + try { + tmp = AtomicReferenceFieldUpdater.newUpdater(QNode.class, + QNode.class, "next"); + + // Test if AtomicReferenceFieldUpdater is really working. + QNode testNode = new QNode(null, false); + tmp.set(testNode, testNode); + if (testNode.next != testNode) { + // Not set as expected - fall back to the safe mode. + throw new Exception(); + } + } catch (Throwable t) { + // Running in a restricted environment with a security manager. + tmp = null; + } + nextUpdater = tmp; + } + + boolean casNext(QNode cmp, QNode val) { + if (nextUpdater != null) { + return nextUpdater.compareAndSet(this, cmp, val); + } else { + return alternativeCasNext(cmp, val); + } + } + + private synchronized boolean alternativeCasNext(QNode cmp, QNode val) { + if (this.next == cmp) { + this.next = val; + return true; + } else { + return false; + } + } + } + + /** + * Padded version of AtomicReference used for head, tail and cleanMe, to + * alleviate contention across threads CASing one vs the other. + */ + public static final class PaddedAtomicReference + extends + AtomicReference { + private static final long serialVersionUID = 4684288940772921317L; + + // enough padding for 64bytes with 4byte refs + @SuppressWarnings("unused") + public Object p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, + pe; + public PaddedAtomicReference(T r) { + super(r); + } + } + + /** head of the queue */ + private final PaddedAtomicReference head; + /** tail of the queue */ + private final PaddedAtomicReference tail; + + /** + * Reference to a cancelled node that might not yet have been unlinked from + * queue because it was the last inserted node when it cancelled. + */ + private final PaddedAtomicReference cleanMe; + + /** + * Tries to cas nh as new head; if successful, unlink old head's next node + * to avoid garbage retention. + */ + private boolean advanceHead(QNode h, QNode nh) { + if (h == this.head.get() && this.head.compareAndSet(h, nh)) { + h.next = h; // forget old next + return true; + } + return false; + } + + /** + * Puts or takes an item. Used for most queue operations (except poll() and + * tryTransfer()). See the similar code in SynchronousQueue for detailed + * explanation. + * + * @param e + * the item or if null, signifies that this is a take + * @param mode + * the wait mode: NOWAIT, TIMEOUT, WAIT + * @param nanos + * timeout in nanosecs, used only if mode is TIMEOUT + * @return an item, or null on failure + */ + private Object xfer(Object e, int mode, long nanos) { + boolean isData = e != null; + QNode s = null; + final PaddedAtomicReference head = this.head; + final PaddedAtomicReference tail = this.tail; + + for (;;) { + QNode t = tail.get(); + QNode h = head.get(); + + if (t != null && (t == h || t.isData == isData)) { + if (s == null) { + s = new QNode(e, isData); + } + QNode last = t.next; + if (last != null) { + if (t == tail.get()) { + tail.compareAndSet(t, last); + } + } else if (t.casNext(null, s)) { + tail.compareAndSet(t, s); + return awaitFulfill(t, s, e, mode, nanos); + } + } + + else if (h != null) { + QNode first = h.next; + if (t == tail.get() && first != null && advanceHead(h, first)) { + Object x = first.get(); + if (x != first && first.compareAndSet(x, e)) { + LockSupport.unpark(first.waiter); + return isData ? e : x; + } + } + } + } + } + + /** + * Version of xfer for poll() and tryTransfer, which simplifies control + * paths both here and in xfer + */ + private Object fulfill(Object e) { + boolean isData = e != null; + final PaddedAtomicReference head = this.head; + final PaddedAtomicReference tail = this.tail; + + for (;;) { + QNode t = tail.get(); + QNode h = head.get(); + + if (t != null && (t == h || t.isData == isData)) { + QNode last = t.next; + if (t == tail.get()) { + if (last != null) { + tail.compareAndSet(t, last); + } else { + return null; + } + } + } else if (h != null) { + QNode first = h.next; + if (t == tail.get() && first != null && advanceHead(h, first)) { + Object x = first.get(); + if (x != first && first.compareAndSet(x, e)) { + LockSupport.unpark(first.waiter); + return isData ? e : x; + } + } + } + } + } + + /** + * Spins/blocks until node s is fulfilled or caller gives up, depending on + * wait mode. + * + * @param pred + * the predecessor of waiting node + * @param s + * the waiting node + * @param e + * the comparison value for checking match + * @param mode + * mode + * @param nanos + * timeout value + * @return matched item, or s if cancelled + */ + private Object awaitFulfill(QNode pred, QNode s, Object e, int mode, + long nanos) { + if (mode == NOWAIT) { + return null; + } + + long lastTime = mode == TIMEOUT ? System.nanoTime() : 0; + Thread w = Thread.currentThread(); + int spins = -1; // set to desired spin count below + for (;;) { + if (w.isInterrupted()) { + s.compareAndSet(e, s); + } + Object x = s.get(); + if (x != e) { // Node was matched or cancelled + advanceHead(pred, s); // unlink if head + if (x == s) { // was cancelled + clean(pred, s); + return null; + } else if (x != null) { + s.set(s); // avoid garbage retention + return x; + } else { + return e; + } + } + if (mode == TIMEOUT) { + long now = System.nanoTime(); + nanos -= now - lastTime; + lastTime = now; + if (nanos <= 0) { + s.compareAndSet(e, s); // try to cancel + continue; + } + } + if (spins < 0) { + QNode h = this.head.get(); // only spin if at head + spins = h != null && h.next == s + ? (mode == TIMEOUT ? maxTimedSpins : maxUntimedSpins) + : 0; + } + if (spins > 0) { + --spins; + } else if (s.waiter == null) { + s.waiter = w; + } else if (mode != TIMEOUT) { + // LockSupport.park(this); + LockSupport.park(); // allows run on java5 + s.waiter = null; + spins = -1; + } else if (nanos > spinForTimeoutThreshold) { + // LockSupport.parkNanos(this, nanos); + LockSupport.parkNanos(nanos); + s.waiter = null; + spins = -1; + } + } + } + + /** + * Returns validated tail for use in cleaning methods + */ + private QNode getValidatedTail() { + for (;;) { + QNode h = this.head.get(); + QNode first = h.next; + if (first != null && first.next == first) { // help advance + advanceHead(h, first); + continue; + } + QNode t = this.tail.get(); + QNode last = t.next; + if (t == this.tail.get()) { + if (last != null) { + this.tail.compareAndSet(t, last); // help advance + } else { + return t; + } + } + } + } + + /** + * Gets rid of cancelled node s with original predecessor pred. + * + * @param pred + * predecessor of cancelled node + * @param s + * the cancelled node + */ + void clean(QNode pred, QNode s) { + Thread w = s.waiter; + if (w != null) { // Wake up thread + s.waiter = null; + if (w != Thread.currentThread()) { + LockSupport.unpark(w); + } + } + /* + * At any given time, exactly one node on list cannot be deleted -- the + * last inserted node. To accommodate this, if we cannot delete s, we + * save its predecessor as "cleanMe", processing the previously saved + * version first. At least one of node s or the node previously saved + * can always be processed, so this always terminates. + */ + while (pred.next == s) { + QNode oldpred = reclean(); // First, help get rid of cleanMe + QNode t = getValidatedTail(); + if (s != t) { // If not tail, try to unsplice + QNode sn = s.next; // s.next == s means s already off list + if (sn == s || pred.casNext(s, sn)) { + break; + } + } else if (oldpred == pred || // Already saved + oldpred == null && this.cleanMe.compareAndSet(null, pred)) { + break; // Postpone cleaning + } + } + } + + /** + * Tries to unsplice the cancelled node held in cleanMe that was previously + * uncleanable because it was at tail. + * + * @return current cleanMe node (or null) + */ + private QNode reclean() { + /* + * cleanMe is, or at one time was, predecessor of cancelled node s that + * was the tail so could not be unspliced. If s is no longer the tail, + * try to unsplice if necessary and make cleanMe slot available. This + * differs from similar code in clean() because we must check that pred + * still points to a cancelled node that must be unspliced -- if not, we + * can (must) clear cleanMe without unsplicing. This can loop only due + * to contention on casNext or clearing cleanMe. + */ + QNode pred; + while ((pred = this.cleanMe.get()) != null) { + QNode t = getValidatedTail(); + QNode s = pred.next; + if (s != t) { + QNode sn; + if (s == null || s == pred || s.get() != s || (sn = s.next) == s + || pred.casNext(s, sn)) { + this.cleanMe.compareAndSet(pred, null); + } + } else { + break; + } + } + return pred; + } + + @SuppressWarnings("unchecked") + E cast(Object e) { + return (E) e; + } + + /** + * Creates an initially empty LinkedTransferQueue. + */ + public LinkedTransferQueue() { + QNode dummy = new QNode(null, false); + this.head = new PaddedAtomicReference(dummy); + this.tail = new PaddedAtomicReference(dummy); + this.cleanMe = new PaddedAtomicReference(null); + } + + /** + * Creates a LinkedTransferQueue initially containing the elements + * of the given collection, added in traversal order of the collection's + * iterator. + * + * @param c + * the collection of elements to initially contain + * @throws NullPointerException + * if the specified collection or any of its elements are null + */ + public LinkedTransferQueue(Collection c) { + this(); + addAll(c); + } + + public void put(E e) throws InterruptedException { + if (e == null) { + throw new NullPointerException(); + } + if (Thread.interrupted()) { + throw new InterruptedException(); + } + xfer(e, NOWAIT, 0); + } + + public boolean offer(E e, long timeout, TimeUnit unit) + throws InterruptedException { + if (e == null) { + throw new NullPointerException(); + } + if (Thread.interrupted()) { + throw new InterruptedException(); + } + xfer(e, NOWAIT, 0); + return true; + } + + public boolean offer(E e) { + if (e == null) { + throw new NullPointerException(); + } + xfer(e, NOWAIT, 0); + return true; + } + + public void transfer(E e) throws InterruptedException { + if (e == null) { + throw new NullPointerException(); + } + if (xfer(e, WAIT, 0) == null) { + Thread.interrupted(); + throw new InterruptedException(); + } + } + + public boolean tryTransfer(E e, long timeout, TimeUnit unit) + throws InterruptedException { + if (e == null) { + throw new NullPointerException(); + } + if (xfer(e, TIMEOUT, unit.toNanos(timeout)) != null) { + return true; + } + if (!Thread.interrupted()) { + return false; + } + throw new InterruptedException(); + } + + public boolean tryTransfer(E e) { + if (e == null) { + throw new NullPointerException(); + } + return fulfill(e) != null; + } + + public E take() throws InterruptedException { + Object e = xfer(null, WAIT, 0); + if (e != null) { + return cast(e); + } + Thread.interrupted(); + throw new InterruptedException(); + } + + public E poll(long timeout, TimeUnit unit) throws InterruptedException { + Object e = xfer(null, TIMEOUT, unit.toNanos(timeout)); + if (e != null || !Thread.interrupted()) { + return cast(e); + } + throw new InterruptedException(); + } + + public E poll() { + return cast(fulfill(null)); + } + + public int drainTo(Collection c) { + if (c == null) { + throw new NullPointerException(); + } + if (c == this) { + throw new IllegalArgumentException(); + } + int n = 0; + E e; + while ((e = poll()) != null) { + c.add(e); + ++n; + } + return n; + } + + public int drainTo(Collection c, int maxElements) { + if (c == null) { + throw new NullPointerException(); + } + if (c == this) { + throw new IllegalArgumentException(); + } + int n = 0; + E e; + while (n < maxElements && (e = poll()) != null) { + c.add(e); + ++n; + } + return n; + } + + // Traversal-based methods + + /** + * Return head after performing any outstanding helping steps + */ + QNode traversalHead() { + for (;;) { + QNode t = this.tail.get(); + QNode h = this.head.get(); + if (h != null && t != null) { + QNode last = t.next; + QNode first = h.next; + if (t == this.tail.get()) { + if (last != null) { + this.tail.compareAndSet(t, last); + } else if (first != null) { + Object x = first.get(); + if (x == first) { + advanceHead(h, first); + } else { + return h; + } + } else { + return h; + } + } + } + } + } + + @Override + public Iterator iterator() { + return new Itr(); + } + + /** + * Iterators. Basic strategy is to traverse list, treating non-data (i.e., + * request) nodes as terminating list. Once a valid data node is found, the + * item is cached so that the next call to next() will return it even if + * subsequently removed. + */ + class Itr implements Iterator { + QNode nextNode; // Next node to return next + QNode currentNode; // last returned node, for remove() + QNode prevNode; // predecessor of last returned node + E nextItem; // Cache of next item, once commited to in next + + Itr() { + this.nextNode = traversalHead(); + advance(); + } + + E advance() { + this.prevNode = this.currentNode; + this.currentNode = this.nextNode; + E x = this.nextItem; + + QNode p = this.nextNode.next; + for (;;) { + if (p == null || !p.isData) { + this.nextNode = null; + this.nextItem = null; + return x; + } + Object item = p.get(); + if (item != p && item != null) { + this.nextNode = p; + this.nextItem = cast(item); + return x; + } + this.prevNode = p; + p = p.next; + } + } + + public boolean hasNext() { + return this.nextNode != null; + } + + public E next() { + if (this.nextNode == null) { + throw new NoSuchElementException(); + } + return advance(); + } + + public void remove() { + QNode p = this.currentNode; + QNode prev = this.prevNode; + if (prev == null || p == null) { + throw new IllegalStateException(); + } + Object x = p.get(); + if (x != null && x != p && p.compareAndSet(x, p)) { + clean(prev, p); + } + } + } + + public E peek() { + for (;;) { + QNode h = traversalHead(); + QNode p = h.next; + if (p == null) { + return null; + } + Object x = p.get(); + if (p != x) { + if (!p.isData) { + return null; + } + if (x != null) { + return cast(x); + } + } + } + } + + @Override + public boolean isEmpty() { + for (;;) { + QNode h = traversalHead(); + QNode p = h.next; + if (p == null) { + return true; + } + Object x = p.get(); + if (p != x) { + if (!p.isData) { + return true; + } + if (x != null) { + return false; + } + } + } + } + + public boolean hasWaitingConsumer() { + for (;;) { + QNode h = traversalHead(); + QNode p = h.next; + if (p == null) { + return false; + } + Object x = p.get(); + if (p != x) { + return !p.isData; + } + } + } + + /** + * Returns the number of elements in this queue. If this queue contains more + * than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + *

+ * Beware that, unlike in most collections, this method is NOT a + * constant-time operation. Because of the asynchronous nature of these + * queues, determining the current number of elements requires an O(n) + * traversal. + * + * @return the number of elements in this queue + */ + @Override + public int size() { + int count = 0; + QNode h = traversalHead(); + for (QNode p = h.next; p != null && p.isData; p = p.next) { + Object x = p.get(); + if (x != null && x != p) { + if (++count == Integer.MAX_VALUE) { + break; + } + } + } + return count; + } + + public int getWaitingConsumerCount() { + int count = 0; + QNode h = traversalHead(); + for (QNode p = h.next; p != null && !p.isData; p = p.next) { + if (p.get() == null) { + if (++count == Integer.MAX_VALUE) { + break; + } + } + } + return count; + } + + public int remainingCapacity() { + return Integer.MAX_VALUE; + } } diff --git a/src/main/java/com/google/code/yanf4j/util/MapBackedSet.java b/src/main/java/com/google/code/yanf4j/util/MapBackedSet.java index b8c966cbb..29084bcd5 100644 --- a/src/main/java/com/google/code/yanf4j/util/MapBackedSet.java +++ b/src/main/java/com/google/code/yanf4j/util/MapBackedSet.java @@ -11,51 +11,51 @@ * A {@link Map}-backed {@link Set}. * * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev: 597692 $, $Date: 2007-11-23 08:56:32 -0700 (Fri, 23 Nov 2007) $ + * @version $Rev: 597692 $, $Date: 2007-11-23 08:56:32 -0700 (Fri, 23 Nov 2007) + * $ */ public class MapBackedSet extends AbstractSet implements Serializable { - private static final long serialVersionUID = -8347878570391674042L; - - protected final Map map; - - public MapBackedSet(Map map) { - this.map = map; - } - - public MapBackedSet(Map map, Collection c) { - this.map = map; - addAll(c); - } - - @Override - public int size() { - return map.size(); - } - - @Override - public boolean contains(Object o) { - return map.containsKey(o); - } - - @Override - public Iterator iterator() { - return map.keySet().iterator(); - } - - @Override - public boolean add(E o) { - return map.put(o, Boolean.TRUE) == null; - } - - @Override - public boolean remove(Object o) { - return map.remove(o) != null; - } - - @Override - public void clear() { - map.clear(); - } -} + private static final long serialVersionUID = -8347878570391674042L; + + protected final Map map; + + public MapBackedSet(Map map) { + this.map = map; + } + + public MapBackedSet(Map map, Collection c) { + this.map = map; + addAll(c); + } + + @Override + public int size() { + return map.size(); + } + @Override + public boolean contains(Object o) { + return map.containsKey(o); + } + + @Override + public Iterator iterator() { + return map.keySet().iterator(); + } + + @Override + public boolean add(E o) { + return map.put(o, Boolean.TRUE) == null; + } + + @Override + public boolean remove(Object o) { + return map.remove(o) != null; + } + + @Override + public void clear() { + map.clear(); + } +} diff --git a/src/main/java/com/google/code/yanf4j/util/ResourcesUtils.java b/src/main/java/com/google/code/yanf4j/util/ResourcesUtils.java index d975562c7..b568660bf 100644 --- a/src/main/java/com/google/code/yanf4j/util/ResourcesUtils.java +++ b/src/main/java/com/google/code/yanf4j/util/ResourcesUtils.java @@ -203,8 +203,8 @@ public static InputStreamReader getResourceAsReader(String resource) * If the resource cannot be found or read * @return The resource */ - public static Reader getResourceAsReader(ClassLoader loader, String resource) - throws IOException { + public static Reader getResourceAsReader(ClassLoader loader, + String resource) throws IOException { return new InputStreamReader(getResourceAsStream(loader, resource)); } diff --git a/src/main/java/com/google/code/yanf4j/util/SelectorFactory.java b/src/main/java/com/google/code/yanf4j/util/SelectorFactory.java index dc2db2a11..86db4be8e 100644 --- a/src/main/java/com/google/code/yanf4j/util/SelectorFactory.java +++ b/src/main/java/com/google/code/yanf4j/util/SelectorFactory.java @@ -30,8 +30,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; - - /** * Temp selector factory,come from grizzly * @@ -39,144 +37,133 @@ */ public class SelectorFactory { - public static final int DEFAULT_MAX_SELECTORS = 20; - - private static final Logger logger = LoggerFactory.getLogger(SelectorFactory.class); - /** - * The timeout before we exit. - */ - public final static long timeout = 5000; - - /** - * The number of Selector to create. - */ - private static int maxSelectors; - - /** - * Cache of Selector - */ - private final static Stack selectors = new Stack(); - - /** - * Creates the Selector - */ - static { - try { - setMaxSelectors(DEFAULT_MAX_SELECTORS); - } - catch (IOException ex) { - logger.warn("SelectorFactory initializing Selector pool", ex); - } - } - - - /** - * Set max selector pool size. - * - * @param size - * max pool size - */ - public final static void setMaxSelectors(int size) throws IOException { - synchronized (selectors) { - if (size < maxSelectors) { - reduce(size); - } - else if (size > maxSelectors) { - grow(size); - } - - maxSelectors = size; - } - } - - - /** - * Returns max selector pool size - * - * @return max pool size - */ - public final static int getMaxSelectors() { - return maxSelectors; - } - - - /** - * Get a exclusive Selector - * - * @return Selector - */ - public final static Selector getSelector() { - synchronized (selectors) { - Selector s = null; - try { - if (selectors.size() != 0) { - s = selectors.pop(); - } - } - catch (EmptyStackException ex) { - } - - int attempts = 0; - try { - while (s == null && attempts < 2) { - selectors.wait(timeout); - try { - if (selectors.size() != 0) { - s = selectors.pop(); - } - } - catch (EmptyStackException ex) { - break; - } - attempts++; - } - } - catch (InterruptedException ex) { - } - return s; - } - } - - - /** - * Return the Selector to the cache - * - * @param s - * Selector - */ - public final static void returnSelector(Selector s) { - synchronized (selectors) { - selectors.push(s); - if (selectors.size() == 1) { - selectors.notify(); - } - } - } - - - /** - * Increase Selector pool size - */ - private static void grow(int size) throws IOException { - for (int i = 0; i < size - maxSelectors; i++) { - selectors.add(Selector.open()); - } - } - - - /** - * Decrease Selector pool size - */ - private static void reduce(int size) { - for (int i = 0; i < maxSelectors - size; i++) { - try { - Selector selector = selectors.pop(); - selector.close(); - } - catch (IOException e) { - logger.error("SelectorFactory.reduce", e); - } - } - } + public static final int DEFAULT_MAX_SELECTORS = 20; + + private static final Logger logger = LoggerFactory + .getLogger(SelectorFactory.class); + /** + * The timeout before we exit. + */ + public final static long timeout = 5000; + + /** + * The number of Selector to create. + */ + private static int maxSelectors; + + /** + * Cache of Selector + */ + private final static Stack selectors = new Stack(); + + /** + * Creates the Selector + */ + static { + try { + setMaxSelectors(DEFAULT_MAX_SELECTORS); + } catch (IOException ex) { + logger.warn("SelectorFactory initializing Selector pool", ex); + } + } + + /** + * Set max selector pool size. + * + * @param size + * max pool size + */ + public final static void setMaxSelectors(int size) throws IOException { + synchronized (selectors) { + if (size < maxSelectors) { + reduce(size); + } else if (size > maxSelectors) { + grow(size); + } + + maxSelectors = size; + } + } + + /** + * Returns max selector pool size + * + * @return max pool size + */ + public final static int getMaxSelectors() { + return maxSelectors; + } + + /** + * Get a exclusive Selector + * + * @return Selector + */ + public final static Selector getSelector() { + synchronized (selectors) { + Selector s = null; + try { + if (selectors.size() != 0) { + s = selectors.pop(); + } + } catch (EmptyStackException ex) { + } + + int attempts = 0; + try { + while (s == null && attempts < 2) { + selectors.wait(timeout); + try { + if (selectors.size() != 0) { + s = selectors.pop(); + } + } catch (EmptyStackException ex) { + break; + } + attempts++; + } + } catch (InterruptedException ex) { + } + return s; + } + } + + /** + * Return the Selector to the cache + * + * @param s + * Selector + */ + public final static void returnSelector(Selector s) { + synchronized (selectors) { + selectors.push(s); + if (selectors.size() == 1) { + selectors.notify(); + } + } + } + + /** + * Increase Selector pool size + */ + private static void grow(int size) throws IOException { + for (int i = 0; i < size - maxSelectors; i++) { + selectors.add(Selector.open()); + } + } + + /** + * Decrease Selector pool size + */ + private static void reduce(int size) { + for (int i = 0; i < maxSelectors - size; i++) { + try { + Selector selector = selectors.pop(); + selector.close(); + } catch (IOException e) { + logger.error("SelectorFactory.reduce", e); + } + } + } } diff --git a/src/main/java/com/google/code/yanf4j/util/ShiftOrByteBufferMatcher.java b/src/main/java/com/google/code/yanf4j/util/ShiftOrByteBufferMatcher.java index 21c8059b5..e4bc2d3db 100644 --- a/src/main/java/com/google/code/yanf4j/util/ShiftOrByteBufferMatcher.java +++ b/src/main/java/com/google/code/yanf4j/util/ShiftOrByteBufferMatcher.java @@ -27,9 +27,6 @@ import com.google.code.yanf4j.buffer.IoBuffer; - - - /** * ByteBuffer matcher based on shift-or algorithm * @@ -38,70 +35,67 @@ */ public class ShiftOrByteBufferMatcher implements ByteBufferMatcher { - private int[] b; - private int lim; - - private int patternLen; - - - public ShiftOrByteBufferMatcher(IoBuffer pat) { - if (pat == null || pat.remaining() == 0) { - throw new IllegalArgumentException("blank buffer"); - } - this.patternLen = pat.remaining(); - preprocess(pat); - } - - - /** - * Ԥ���� - * - * @param pat - */ - private void preprocess(IoBuffer pat) { - this.b = new int[256]; - this.lim = 0; - for (int i = 0; i < 256; i++) { - this.b[i] = ~0; - - } - for (int i = 0, j = 1; i < this.patternLen; i++, j <<= 1) { - this.b[ByteBufferUtils.uByte(pat.get(i))] &= ~j; - this.lim |= j; - } - this.lim = ~(this.lim >> 1); - - } - - - public final List matchAll(IoBuffer buffer) { - List matches = new ArrayList(); - int bufferLimit = buffer.limit(); - int state = ~0; - for (int pos = buffer.position(); pos < bufferLimit; pos++) { - state <<= 1; - state |= this.b[ByteBufferUtils.uByte(buffer.get(pos))]; - if (state < this.lim) { - matches.add(pos - this.patternLen + 1); - } - } - return matches; - } - - - public final int matchFirst(IoBuffer buffer) { - if (buffer == null) { - return -1; - } - int bufferLimit = buffer.limit(); - int state = ~0; - for (int pos = buffer.position(); pos < bufferLimit; pos++) { - state = (state <<= 1) | this.b[ByteBufferUtils.uByte(buffer.get(pos))]; - if (state < this.lim) { - return pos - this.patternLen + 1; - } - } - return -1; - } + private int[] b; + private int lim; + + private int patternLen; + + public ShiftOrByteBufferMatcher(IoBuffer pat) { + if (pat == null || pat.remaining() == 0) { + throw new IllegalArgumentException("blank buffer"); + } + this.patternLen = pat.remaining(); + preprocess(pat); + } + + /** + * Ԥ���� + * + * @param pat + */ + private void preprocess(IoBuffer pat) { + this.b = new int[256]; + this.lim = 0; + for (int i = 0; i < 256; i++) { + this.b[i] = ~0; + + } + for (int i = 0, j = 1; i < this.patternLen; i++, j <<= 1) { + this.b[ByteBufferUtils.uByte(pat.get(i))] &= ~j; + this.lim |= j; + } + this.lim = ~(this.lim >> 1); + + } + + public final List matchAll(IoBuffer buffer) { + List matches = new ArrayList(); + int bufferLimit = buffer.limit(); + int state = ~0; + for (int pos = buffer.position(); pos < bufferLimit; pos++) { + state <<= 1; + state |= this.b[ByteBufferUtils.uByte(buffer.get(pos))]; + if (state < this.lim) { + matches.add(pos - this.patternLen + 1); + } + } + return matches; + } + + public final int matchFirst(IoBuffer buffer) { + if (buffer == null) { + return -1; + } + int bufferLimit = buffer.limit(); + int state = ~0; + for (int pos = buffer.position(); pos < bufferLimit; pos++) { + state = (state <<= 1) + | this.b[ByteBufferUtils.uByte(buffer.get(pos))]; + if (state < this.lim) { + return pos - this.patternLen + 1; + } + } + return -1; + } } diff --git a/src/main/java/com/google/code/yanf4j/util/SystemUtils.java b/src/main/java/com/google/code/yanf4j/util/SystemUtils.java index 56e92db09..c2c6ccc24 100644 --- a/src/main/java/com/google/code/yanf4j/util/SystemUtils.java +++ b/src/main/java/com/google/code/yanf4j/util/SystemUtils.java @@ -139,16 +139,19 @@ public static final Selector openSelector() throws IOException { } - public static final String getRawAddress(InetSocketAddress inetSocketAddress) { + public static final String getRawAddress( + InetSocketAddress inetSocketAddress) { InetAddress address = inetSocketAddress.getAddress(); - return address != null ? address.getHostAddress() : inetSocketAddress - .getHostName(); + return address != null + ? address.getHostAddress() + : inetSocketAddress.getHostName(); } public static final Queue createTransferQueue() { try { - return (Queue) Class.forName( - "java.util.concurrent.LinkedTransferQueue").newInstance(); + return (Queue) Class + .forName("java.util.concurrent.LinkedTransferQueue") + .newInstance(); } catch (Exception e) { return new LinkedTransferQueue(); } diff --git a/src/main/java/com/google/code/yanf4j/util/TransferQueue.java b/src/main/java/com/google/code/yanf4j/util/TransferQueue.java index 7f1f12b43..4c79da476 100644 --- a/src/main/java/com/google/code/yanf4j/util/TransferQueue.java +++ b/src/main/java/com/google/code/yanf4j/util/TransferQueue.java @@ -7,111 +7,125 @@ import java.util.concurrent.*; /** - * A {@link BlockingQueue} in which producers may wait for consumers - * to receive elements. A {@code TransferQueue} may be useful for - * example in message passing applications in which producers - * sometimes (using method {@code transfer}) await receipt of - * elements by consumers invoking {@code take} or {@code poll}, - * while at other times enqueue elements (via method {@code put}) - * without waiting for receipt. Non-blocking and time-out versions of - * {@code tryTransfer} are also available. A TransferQueue may also - * be queried via {@code hasWaitingConsumer} whether there are any - * threads waiting for items, which is a converse analogy to a - * {@code peek} operation. + * A {@link BlockingQueue} in which producers may wait for consumers to receive + * elements. A {@code TransferQueue} may be useful for example in message + * passing applications in which producers sometimes (using method + * {@code transfer}) await receipt of elements by consumers invoking + * {@code take} or {@code poll}, while at other times enqueue elements (via + * method {@code put}) without waiting for receipt. Non-blocking and time-out + * versions of {@code tryTransfer} are also available. A TransferQueue may also + * be queried via {@code hasWaitingConsumer} whether there are any threads + * waiting for items, which is a converse analogy to a {@code peek} operation. * - *

Like any {@code BlockingQueue}, a {@code TransferQueue} may be - * capacity bounded. If so, an attempted {@code transfer} operation - * may initially block waiting for available space, and/or - * subsequently block waiting for reception by a consumer. Note that - * in a queue with zero capacity, such as {@link SynchronousQueue}, - * {@code put} and {@code transfer} are effectively synonymous. + *

+ * Like any {@code BlockingQueue}, a {@code TransferQueue} may be capacity + * bounded. If so, an attempted {@code transfer} operation may initially block + * waiting for available space, and/or subsequently block waiting for reception + * by a consumer. Note that in a queue with zero capacity, such as + * {@link SynchronousQueue}, {@code put} and {@code transfer} are effectively + * synonymous. * - *

This interface is a member of the - * - * Java Collections Framework. + *

+ * This interface is a member of the + * Java + * Collections Framework. * * @since 1.7 * @author Doug Lea - * @param the type of elements held in this collection + * @param + * the type of elements held in this collection */ public interface TransferQueue extends BlockingQueue { - /** - * Transfers the specified element if there exists a consumer - * already waiting to receive it, otherwise returning {@code false} - * without enqueuing the element. - * - * @param e the element to transfer - * @return {@code true} if the element was transferred, else - * {@code false} - * @throws ClassCastException if the class of the specified element - * prevents it from being added to this queue - * @throws NullPointerException if the specified element is null - * @throws IllegalArgumentException if some property of the specified - * element prevents it from being added to this queue - */ - boolean tryTransfer(E e); + /** + * Transfers the specified element if there exists a consumer already + * waiting to receive it, otherwise returning {@code false} without + * enqueuing the element. + * + * @param e + * the element to transfer + * @return {@code true} if the element was transferred, else {@code false} + * @throws ClassCastException + * if the class of the specified element prevents it from being + * added to this queue + * @throws NullPointerException + * if the specified element is null + * @throws IllegalArgumentException + * if some property of the specified element prevents it from + * being added to this queue + */ + boolean tryTransfer(E e); - /** - * Inserts the specified element into this queue, waiting if - * necessary for space to become available and the element to be - * dequeued by a consumer invoking {@code take} or {@code poll}. - * - * @param e the element to transfer - * @throws InterruptedException if interrupted while waiting, - * in which case the element is not enqueued. - * @throws ClassCastException if the class of the specified element - * prevents it from being added to this queue - * @throws NullPointerException if the specified element is null - * @throws IllegalArgumentException if some property of the specified - * element prevents it from being added to this queue - */ - void transfer(E e) throws InterruptedException; + /** + * Inserts the specified element into this queue, waiting if necessary for + * space to become available and the element to be dequeued by a consumer + * invoking {@code take} or {@code poll}. + * + * @param e + * the element to transfer + * @throws InterruptedException + * if interrupted while waiting, in which case the element is + * not enqueued. + * @throws ClassCastException + * if the class of the specified element prevents it from being + * added to this queue + * @throws NullPointerException + * if the specified element is null + * @throws IllegalArgumentException + * if some property of the specified element prevents it from + * being added to this queue + */ + void transfer(E e) throws InterruptedException; - /** - * Inserts the specified element into this queue, waiting up to - * the specified wait time if necessary for space to become - * available and the element to be dequeued by a consumer invoking - * {@code take} or {@code poll}. - * - * @param e the element to transfer - * @param timeout how long to wait before giving up, in units of - * {@code unit} - * @param unit a {@code TimeUnit} determining how to interpret the - * {@code timeout} parameter - * @return {@code true} if successful, or {@code false} if - * the specified waiting time elapses before completion, - * in which case the element is not enqueued. - * @throws InterruptedException if interrupted while waiting, - * in which case the element is not enqueued. - * @throws ClassCastException if the class of the specified element - * prevents it from being added to this queue - * @throws NullPointerException if the specified element is null - * @throws IllegalArgumentException if some property of the specified - * element prevents it from being added to this queue - */ - boolean tryTransfer(E e, long timeout, TimeUnit unit) - throws InterruptedException; + /** + * Inserts the specified element into this queue, waiting up to the + * specified wait time if necessary for space to become available and the + * element to be dequeued by a consumer invoking {@code take} or + * {@code poll}. + * + * @param e + * the element to transfer + * @param timeout + * how long to wait before giving up, in units of {@code unit} + * @param unit + * a {@code TimeUnit} determining how to interpret the + * {@code timeout} parameter + * @return {@code true} if successful, or {@code false} if the specified + * waiting time elapses before completion, in which case the element + * is not enqueued. + * @throws InterruptedException + * if interrupted while waiting, in which case the element is + * not enqueued. + * @throws ClassCastException + * if the class of the specified element prevents it from being + * added to this queue + * @throws NullPointerException + * if the specified element is null + * @throws IllegalArgumentException + * if some property of the specified element prevents it from + * being added to this queue + */ + boolean tryTransfer(E e, long timeout, TimeUnit unit) + throws InterruptedException; - /** - * Returns {@code true} if there is at least one consumer waiting - * to dequeue an element via {@code take} or {@code poll}. - * The return value represents a momentary state of affairs. - * - * @return {@code true} if there is at least one waiting consumer - */ - boolean hasWaitingConsumer(); + /** + * Returns {@code true} if there is at least one consumer waiting to dequeue + * an element via {@code take} or {@code poll}. The return value represents + * a momentary state of affairs. + * + * @return {@code true} if there is at least one waiting consumer + */ + boolean hasWaitingConsumer(); - /** - * Returns an estimate of the number of consumers waiting to - * dequeue elements via {@code take} or {@code poll}. The return - * value is an approximation of a momentary state of affairs, that - * may be inaccurate if consumers have completed or given up - * waiting. The value may be useful for monitoring and heuristics, - * but not for synchronization control. Implementations of this - * method are likely to be noticeably slower than those for - * {@link #hasWaitingConsumer}. - * - * @return the number of consumers waiting to dequeue elements - */ - int getWaitingConsumerCount(); + /** + * Returns an estimate of the number of consumers waiting to dequeue + * elements via {@code take} or {@code poll}. The return value is an + * approximation of a momentary state of affairs, that may be inaccurate if + * consumers have completed or given up waiting. The value may be useful for + * monitoring and heuristics, but not for synchronization control. + * Implementations of this method are likely to be noticeably slower than + * those for {@link #hasWaitingConsumer}. + * + * @return the number of consumers waiting to dequeue elements + */ + int getWaitingConsumerCount(); } diff --git a/src/main/java/com/google/code/yanf4j/util/WorkerThreadFactory.java b/src/main/java/com/google/code/yanf4j/util/WorkerThreadFactory.java index 7d80c6b86..2244ee6c5 100644 --- a/src/main/java/com/google/code/yanf4j/util/WorkerThreadFactory.java +++ b/src/main/java/com/google/code/yanf4j/util/WorkerThreadFactory.java @@ -40,8 +40,9 @@ public class WorkerThreadFactory implements ThreadFactory { public WorkerThreadFactory(ThreadGroup group, String prefix) { if (group == null) { SecurityManager s = System.getSecurityManager(); - this.group = (s != null) ? s.getThreadGroup() : Thread - .currentThread().getThreadGroup(); + this.group = (s != null) + ? s.getThreadGroup() + : Thread.currentThread().getThreadGroup(); } else { this.group = group; } @@ -53,9 +54,9 @@ public WorkerThreadFactory(ThreadGroup group, String prefix) { + "-thread-"; } } - - public WorkerThreadFactory(String prefix){ - this(null,prefix); + + public WorkerThreadFactory(String prefix) { + this(null, prefix); } public WorkerThreadFactory() { @@ -63,8 +64,8 @@ public WorkerThreadFactory() { } public Thread newThread(Runnable r) { - Thread t = new Thread(this.group, r, this.namePrefix - + this.threadNumber.getAndIncrement(), 0); + Thread t = new Thread(this.group, r, + this.namePrefix + this.threadNumber.getAndIncrement(), 0); t.setDaemon(true); if (t.getPriority() != Thread.NORM_PRIORITY) { t.setPriority(Thread.NORM_PRIORITY); diff --git a/src/main/java/net/rubyeye/xmemcached/CommandFactory.java b/src/main/java/net/rubyeye/xmemcached/CommandFactory.java index dc9440d52..455e2eda5 100644 --- a/src/main/java/net/rubyeye/xmemcached/CommandFactory.java +++ b/src/main/java/net/rubyeye/xmemcached/CommandFactory.java @@ -107,7 +107,8 @@ public Command createGetCommand(final String key, final byte[] keyBytes, * @return */ public Command createGetMultiCommand(Collection keys, - CountDownLatch latch, CommandType cmdType, Transcoder transcoder); + CountDownLatch latch, CommandType cmdType, + Transcoder transcoder); /** * create a incr/decr command @@ -182,9 +183,9 @@ public Command createAddCommand(final String key, final byte[] keyBytes, * @param transcoder * @return */ - public Command createReplaceCommand(final String key, - final byte[] keyBytes, final int exp, final Object value, - boolean noreply, Transcoder transcoder); + public Command createReplaceCommand(final String key, final byte[] keyBytes, + final int exp, final Object value, boolean noreply, + Transcoder transcoder); /** * create a append command @@ -209,9 +210,8 @@ public Command createAppendCommand(final String key, final byte[] keyBytes, * @param transcoder * @return */ - public Command createPrependCommand(final String key, - final byte[] keyBytes, final Object value, boolean noreply, - Transcoder transcoder); + public Command createPrependCommand(final String key, final byte[] keyBytes, + final Object value, boolean noreply, Transcoder transcoder); /** * Create a verbosity command @@ -251,8 +251,8 @@ public Command createAuthStartCommand(String mechanism, * @param authData * @return */ - public Command createAuthStepCommand(String mechanism, - CountDownLatch latch, byte[] authData); + public Command createAuthStepCommand(String mechanism, CountDownLatch latch, + byte[] authData); /** * create a quit command @@ -296,8 +296,8 @@ public Command createGetAndTouchCommand(final String key, * Create a AWS ElasticCache config command, only supports Cache Engine * Version 1.4.14 or Higher. * - * @see Adding + * @see Adding * Auto Discovery To Your Client Library * @param subCommand * @param key diff --git a/src/main/java/net/rubyeye/xmemcached/Counter.java b/src/main/java/net/rubyeye/xmemcached/Counter.java index 9f9df6c64..80a2e4451 100644 --- a/src/main/java/net/rubyeye/xmemcached/Counter.java +++ b/src/main/java/net/rubyeye/xmemcached/Counter.java @@ -22,10 +22,9 @@ public int hashCode() { int result = 1; result = prime * result + ((this.key == null) ? 0 : this.key.hashCode()); - result = prime - * result - + ((this.memcachedClient == null) ? 0 : this.memcachedClient - .hashCode()); + result = prime * result + ((this.memcachedClient == null) + ? 0 + : this.memcachedClient.hashCode()); return result; } @@ -70,8 +69,8 @@ public final String getKey() { * @throws InterruptedException * @throws TimeoutException */ - public long get() throws MemcachedException, InterruptedException, - TimeoutException { + public long get() + throws MemcachedException, InterruptedException, TimeoutException { Object result = this.memcachedClient.get(this.key); if (result == null) { throw new MemcachedClientException("key is not existed."); @@ -91,8 +90,8 @@ public long get() throws MemcachedException, InterruptedException, * @throws InterruptedException * @throws TimeoutException */ - public void set(long value) throws MemcachedException, - InterruptedException, TimeoutException { + public void set(long value) + throws MemcachedException, InterruptedException, TimeoutException { this.memcachedClient.set(this.key, 0, String.valueOf(value)); } @@ -119,8 +118,8 @@ public Counter(MemcachedClient memcachedClient, String key, * @throws InterruptedException * @throws TimeoutException */ - public long incrementAndGet() throws MemcachedException, - InterruptedException, TimeoutException { + public long incrementAndGet() + throws MemcachedException, InterruptedException, TimeoutException { return this.memcachedClient.incr(this.key, 1, this.initialValue); } @@ -132,8 +131,8 @@ public long incrementAndGet() throws MemcachedException, * @throws InterruptedException * @throws TimeoutException */ - public long decrementAndGet() throws MemcachedException, - InterruptedException, TimeoutException { + public long decrementAndGet() + throws MemcachedException, InterruptedException, TimeoutException { return this.memcachedClient.decr(this.key, 1, this.initialValue); } @@ -146,11 +145,11 @@ public long decrementAndGet() throws MemcachedException, * @throws InterruptedException * @throws TimeoutException */ - public long addAndGet(long delta) throws MemcachedException, - InterruptedException, TimeoutException { + public long addAndGet(long delta) + throws MemcachedException, InterruptedException, TimeoutException { if (delta >= 0) { - return this.memcachedClient - .incr(this.key, delta, this.initialValue); + return this.memcachedClient.incr(this.key, delta, + this.initialValue); } else { return this.memcachedClient.decr(this.key, -delta, this.initialValue); diff --git a/src/main/java/net/rubyeye/xmemcached/GetsResponse.java b/src/main/java/net/rubyeye/xmemcached/GetsResponse.java index d3f00d4f2..c9e80f716 100644 --- a/src/main/java/net/rubyeye/xmemcached/GetsResponse.java +++ b/src/main/java/net/rubyeye/xmemcached/GetsResponse.java @@ -21,7 +21,7 @@ public final class GetsResponse { private final long cas; private final T value; - public GetsResponse(final long cas,final T value) { + public GetsResponse(final long cas, final T value) { super(); this.cas = cas; this.value = value; @@ -35,7 +35,6 @@ public T getValue() { return this.value; } - @Override public int hashCode() { final int prime = 31; @@ -74,8 +73,7 @@ public boolean equals(Object obj) { @Override public String toString() { - return "GetsResponse[cas=" + this.cas + ",value=" - + this.value + "]"; + return "GetsResponse[cas=" + this.cas + ",value=" + this.value + "]"; } } diff --git a/src/main/java/net/rubyeye/xmemcached/HashAlgorithm.java b/src/main/java/net/rubyeye/xmemcached/HashAlgorithm.java index e4b61cf7b..3acbd9eda 100644 --- a/src/main/java/net/rubyeye/xmemcached/HashAlgorithm.java +++ b/src/main/java/net/rubyeye/xmemcached/HashAlgorithm.java @@ -87,111 +87,112 @@ public enum HashAlgorithm { public long hash(final String k) { long rv = 0; switch (this) { - case NATIVE_HASH: - rv = k.hashCode(); - break; - case CRC32_HASH: - // return (crc32(shift) >> 16) & 0x7fff; - CRC32 crc32 = new CRC32(); - crc32.update(ByteUtils.getBytes(k)); - rv = crc32.getValue() >> 16 & 0x7fff; - break; - case FNV1_64_HASH: { - // Thanks to pierre@demartines.com for the pointer - rv = FNV_64_INIT; - int len = k.length(); - for (int i = 0; i < len; i++) { - rv *= FNV_64_PRIME; - rv ^= k.charAt(i); - } - } - break; - case FNV1A_64_HASH: { - rv = FNV_64_INIT; - int len = k.length(); - for (int i = 0; i < len; i++) { - rv ^= k.charAt(i); - rv *= FNV_64_PRIME; - } - } - break; - case FNV1_32_HASH: { - rv = FNV_32_INIT; - int len = k.length(); - for (int i = 0; i < len; i++) { - rv *= FNV_32_PRIME; - rv ^= k.charAt(i); - } - } - break; - case FNV1A_32_HASH: { - rv = FNV_32_INIT; - int len = k.length(); - for (int i = 0; i < len; i++) { - rv ^= k.charAt(i); - rv *= FNV_32_PRIME; - } - } - break; - case ELECTION_HASH: - case KETAMA_HASH: - byte[] bKey = computeMd5(k); - rv = (long) (bKey[3] & 0xFF) << 24 | (long) (bKey[2] & 0xFF) << 16 - | (long) (bKey[1] & 0xFF) << 8 | bKey[0] & 0xFF; - break; - - case MYSQL_HASH: - int nr2 = 4; - for (int i = 0; i < k.length(); i++) { - rv ^= ((rv & 63) + nr2) * k.charAt(i) + (rv << 8); - nr2 += 3; - } - break; - case ELF_HASH: - long x = 0; - for (int i = 0; i < k.length(); i++) { - rv = (rv << 4) + k.charAt(i); - if ((x = rv & 0xF0000000L) != 0) { - rv ^= x >> 24; - rv &= ~x; + case NATIVE_HASH : + rv = k.hashCode(); + break; + case CRC32_HASH : + // return (crc32(shift) >> 16) & 0x7fff; + CRC32 crc32 = new CRC32(); + crc32.update(ByteUtils.getBytes(k)); + rv = crc32.getValue() >> 16 & 0x7fff; + break; + case FNV1_64_HASH : { + // Thanks to pierre@demartines.com for the pointer + rv = FNV_64_INIT; + int len = k.length(); + for (int i = 0; i < len; i++) { + rv *= FNV_64_PRIME; + rv ^= k.charAt(i); } } - rv = rv & 0x7FFFFFFF; - break; - case RS_HASH: - long b = 378551; - long a = 63689; - for (int i = 0; i < k.length(); i++) { - rv = rv * a + k.charAt(i); - a *= b; + break; + case FNV1A_64_HASH : { + rv = FNV_64_INIT; + int len = k.length(); + for (int i = 0; i < len; i++) { + rv ^= k.charAt(i); + rv *= FNV_64_PRIME; + } } - rv = rv & 0x7FFFFFFF; - break; - case LUA_HASH: - int step = (k.length() >> 5) + 1; - rv = k.length(); - for (int len = k.length(); len >= step; len -= step) { - rv = rv ^ (rv << 5) + (rv >> 2) + k.charAt(len - 1); + break; + case FNV1_32_HASH : { + rv = FNV_32_INIT; + int len = k.length(); + for (int i = 0; i < len; i++) { + rv *= FNV_32_PRIME; + rv ^= k.charAt(i); + } } - break; - case ONE_AT_A_TIME: - try { - int hash = 0; - for (byte bt : k.getBytes("utf-8")) { - hash += (bt & 0xFF); - hash += (hash << 10); - hash ^= (hash >>> 6); + break; + case FNV1A_32_HASH : { + rv = FNV_32_INIT; + int len = k.length(); + for (int i = 0; i < len; i++) { + rv ^= k.charAt(i); + rv *= FNV_32_PRIME; } - hash += (hash << 3); - hash ^= (hash >>> 11); - hash += (hash << 15); - rv = hash; - } catch (UnsupportedEncodingException e) { - throw new IllegalStateException("Hash function error", e); } - break; - default: - assert false; + break; + case ELECTION_HASH : + case KETAMA_HASH : + byte[] bKey = computeMd5(k); + rv = (long) (bKey[3] & 0xFF) << 24 + | (long) (bKey[2] & 0xFF) << 16 + | (long) (bKey[1] & 0xFF) << 8 | bKey[0] & 0xFF; + break; + + case MYSQL_HASH : + int nr2 = 4; + for (int i = 0; i < k.length(); i++) { + rv ^= ((rv & 63) + nr2) * k.charAt(i) + (rv << 8); + nr2 += 3; + } + break; + case ELF_HASH : + long x = 0; + for (int i = 0; i < k.length(); i++) { + rv = (rv << 4) + k.charAt(i); + if ((x = rv & 0xF0000000L) != 0) { + rv ^= x >> 24; + rv &= ~x; + } + } + rv = rv & 0x7FFFFFFF; + break; + case RS_HASH : + long b = 378551; + long a = 63689; + for (int i = 0; i < k.length(); i++) { + rv = rv * a + k.charAt(i); + a *= b; + } + rv = rv & 0x7FFFFFFF; + break; + case LUA_HASH : + int step = (k.length() >> 5) + 1; + rv = k.length(); + for (int len = k.length(); len >= step; len -= step) { + rv = rv ^ (rv << 5) + (rv >> 2) + k.charAt(len - 1); + } + break; + case ONE_AT_A_TIME : + try { + int hash = 0; + for (byte bt : k.getBytes("utf-8")) { + hash += (bt & 0xFF); + hash += (hash << 10); + hash ^= (hash >>> 6); + } + hash += (hash << 3); + hash ^= (hash >>> 11); + hash += (hash << 15); + rv = hash; + } catch (UnsupportedEncodingException e) { + throw new IllegalStateException("Hash function error", e); + } + break; + default : + assert false; } return rv & 0xffffffffL; /* Convert to unsigned 32-bits */ diff --git a/src/main/java/net/rubyeye/xmemcached/KeyIterator.java b/src/main/java/net/rubyeye/xmemcached/KeyIterator.java index 4a0972fe2..43e27a396 100644 --- a/src/main/java/net/rubyeye/xmemcached/KeyIterator.java +++ b/src/main/java/net/rubyeye/xmemcached/KeyIterator.java @@ -32,8 +32,8 @@ public interface KeyIterator { * ,MemcachedException,TimeoutException,InterruptedException * */ - public String next() throws MemcachedException, TimeoutException, - InterruptedException; + public String next() + throws MemcachedException, TimeoutException, InterruptedException; /** * Check if the iterator has more keys. diff --git a/src/main/java/net/rubyeye/xmemcached/MemcachedClient.java b/src/main/java/net/rubyeye/xmemcached/MemcachedClient.java index a2ae0f4ab..38d40a54b 100644 --- a/src/main/java/net/rubyeye/xmemcached/MemcachedClient.java +++ b/src/main/java/net/rubyeye/xmemcached/MemcachedClient.java @@ -85,8 +85,8 @@ public interface MemcachedClient { public static final long DEFAULT_HEAL_SESSION_INTERVAL = 2000; int MAX_QUEUED_NOPS = 40000; - int DYNAMIC_MAX_QUEUED_NOPS = (int) (MAX_QUEUED_NOPS * (Runtime - .getRuntime().maxMemory() / 1024.0 / 1024.0 / 1024.0)); + int DYNAMIC_MAX_QUEUED_NOPS = (int) (MAX_QUEUED_NOPS + * (Runtime.getRuntime().maxMemory() / 1024.0 / 1024.0 / 1024.0)); /** * Default max queued noreply operations number.It is calcuated dynamically @@ -94,7 +94,8 @@ public interface MemcachedClient { * * @since 1.3.8 */ - public static final int DEFAULT_MAX_QUEUED_NOPS = DYNAMIC_MAX_QUEUED_NOPS > MAX_QUEUED_NOPS ? MAX_QUEUED_NOPS + public static final int DEFAULT_MAX_QUEUED_NOPS = DYNAMIC_MAX_QUEUED_NOPS > MAX_QUEUED_NOPS + ? MAX_QUEUED_NOPS : DYNAMIC_MAX_QUEUED_NOPS; /** @@ -225,8 +226,8 @@ public void addServer(final InetSocketAddress inetSocketAddress) * @throws MemcachedException */ public T get(final String key, final long timeout, - final Transcoder transcoder) throws TimeoutException, - InterruptedException, MemcachedException; + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException; public T get(final String key, final long timeout) throws TimeoutException, InterruptedException, MemcachedException; @@ -234,8 +235,8 @@ public T get(final String key, final long timeout) public T get(final String key, final Transcoder transcoder) throws TimeoutException, InterruptedException, MemcachedException; - public T get(final String key) throws TimeoutException, - InterruptedException, MemcachedException; + public T get(final String key) + throws TimeoutException, InterruptedException, MemcachedException; /** * Just like get,But it return a GetsResponse,include cas value for cas @@ -254,8 +255,8 @@ public T get(final String key) throws TimeoutException, * @throws MemcachedException */ public GetsResponse gets(final String key, final long timeout, - final Transcoder transcoder) throws TimeoutException, - InterruptedException, MemcachedException; + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException; /** * @see #gets(String, long, Transcoder) @@ -266,8 +267,8 @@ public GetsResponse gets(final String key, final long timeout, * @throws InterruptedException * @throws MemcachedException */ - public GetsResponse gets(final String key) throws TimeoutException, - InterruptedException, MemcachedException; + public GetsResponse gets(final String key) + throws TimeoutException, InterruptedException, MemcachedException; /** * @see #gets(String, long, Transcoder) @@ -294,8 +295,8 @@ public GetsResponse gets(final String key, final long timeout) */ @SuppressWarnings("unchecked") public GetsResponse gets(final String key, - final Transcoder transcoder) throws TimeoutException, - InterruptedException, MemcachedException; + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException; /** * Bulk get items @@ -314,7 +315,7 @@ public GetsResponse gets(final String key, */ public Map get(final Collection keyCollections, final long opTimeout, final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException; + throws TimeoutException, InterruptedException, MemcachedException; /** * @see #get(Collection, long, Transcoder) @@ -327,8 +328,8 @@ public Map get(final Collection keyCollections, * @throws MemcachedException */ public Map get(final Collection keyCollections, - final Transcoder transcoder) throws TimeoutException, - InterruptedException, MemcachedException; + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException; /** * @see #get(Collection, long, Transcoder) @@ -353,8 +354,8 @@ public Map get(final Collection keyCollections) * @throws MemcachedException */ public Map get(final Collection keyCollections, - final long timeout) throws TimeoutException, InterruptedException, - MemcachedException; + final long timeout) + throws TimeoutException, InterruptedException, MemcachedException; /** * Bulk gets items @@ -374,8 +375,8 @@ public Map get(final Collection keyCollections, */ public Map> gets( final Collection keyCollections, final long opTime, - final Transcoder transcoder) throws TimeoutException, - InterruptedException, MemcachedException; + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException; /** * @see #gets(Collection, long, Transcoder) @@ -387,8 +388,8 @@ public Map> gets( * @throws MemcachedException */ public Map> gets( - final Collection keyCollections) throws TimeoutException, - InterruptedException, MemcachedException; + final Collection keyCollections) + throws TimeoutException, InterruptedException, MemcachedException; /** * @see #gets(Collection, long, Transcoder) @@ -402,7 +403,7 @@ public Map> gets( */ public Map> gets( final Collection keyCollections, final long timeout) - throws TimeoutException, InterruptedException, MemcachedException; + throws TimeoutException, InterruptedException, MemcachedException; /** * @see #gets(Collection, long, Transcoder) @@ -416,8 +417,8 @@ public Map> gets( */ public Map> gets( final Collection keyCollections, - final Transcoder transcoder) throws TimeoutException, - InterruptedException, MemcachedException; + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException; /** * Store key-value item to memcached @@ -441,7 +442,7 @@ public Map> gets( */ public boolean set(final String key, final int exp, final T value, final Transcoder transcoder, final long timeout) - throws TimeoutException, InterruptedException, MemcachedException; + throws TimeoutException, InterruptedException, MemcachedException; /** * @see #set(String, int, Object, Transcoder, long) @@ -453,15 +454,15 @@ public boolean set(final String key, final int exp, final Object value) * @see #set(String, int, Object, Transcoder, long) */ public boolean set(final String key, final int exp, final Object value, - final long timeout) throws TimeoutException, InterruptedException, - MemcachedException; + final long timeout) + throws TimeoutException, InterruptedException, MemcachedException; /** * @see #set(String, int, Object, Transcoder, long) */ public boolean set(final String key, final int exp, final T value, - final Transcoder transcoder) throws TimeoutException, - InterruptedException, MemcachedException; + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException; /** * Store key-value item to memcached,doesn't wait for reply @@ -495,7 +496,7 @@ public void setWithNoReply(final String key, final int exp, */ public void setWithNoReply(final String key, final int exp, final T value, final Transcoder transcoder) - throws InterruptedException, MemcachedException; + throws InterruptedException, MemcachedException; /** * Add key-value item to memcached, success only when the key is not exists @@ -516,7 +517,7 @@ public void setWithNoReply(final String key, final int exp, */ public boolean add(final String key, final int exp, final T value, final Transcoder transcoder, final long timeout) - throws TimeoutException, InterruptedException, MemcachedException; + throws TimeoutException, InterruptedException, MemcachedException; /** * @see #add(String, int, Object, Transcoder, long) @@ -543,8 +544,8 @@ public boolean add(final String key, final int exp, final Object value) * @throws MemcachedException */ public boolean add(final String key, final int exp, final Object value, - final long timeout) throws TimeoutException, InterruptedException, - MemcachedException; + final long timeout) + throws TimeoutException, InterruptedException, MemcachedException; /** * @see #add(String, int, Object, Transcoder, long) @@ -560,8 +561,8 @@ public boolean add(final String key, final int exp, final Object value, * @throws MemcachedException */ public boolean add(final String key, final int exp, final T value, - final Transcoder transcoder) throws TimeoutException, - InterruptedException, MemcachedException; + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException; /** * Add key-value item to memcached, success only when the key is not exists @@ -595,7 +596,7 @@ public void addWithNoReply(final String key, final int exp, */ public void addWithNoReply(final String key, final int exp, final T value, final Transcoder transcoder) - throws InterruptedException, MemcachedException; + throws InterruptedException, MemcachedException; /** * Replace the key's data item in memcached,success only when the key's data @@ -616,7 +617,7 @@ public void addWithNoReply(final String key, final int exp, */ public boolean replace(final String key, final int exp, final T value, final Transcoder transcoder, final long timeout) - throws TimeoutException, InterruptedException, MemcachedException; + throws TimeoutException, InterruptedException, MemcachedException; /** * @see #replace(String, int, Object, Transcoder, long) @@ -643,8 +644,8 @@ public boolean replace(final String key, final int exp, final Object value) * @throws MemcachedException */ public boolean replace(final String key, final int exp, final Object value, - final long timeout) throws TimeoutException, InterruptedException, - MemcachedException; + final long timeout) + throws TimeoutException, InterruptedException, MemcachedException; /** * @see #replace(String, int, Object, Transcoder, long) @@ -659,8 +660,8 @@ public boolean replace(final String key, final int exp, final Object value, * @throws MemcachedException */ public boolean replace(final String key, final int exp, final T value, - final Transcoder transcoder) throws TimeoutException, - InterruptedException, MemcachedException; + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException; /** * Replace the key's data item in memcached,success only when the key's data @@ -693,7 +694,7 @@ public void replaceWithNoReply(final String key, final int exp, */ public void replaceWithNoReply(final String key, final int exp, final T value, final Transcoder transcoder) - throws InterruptedException, MemcachedException; + throws InterruptedException, MemcachedException; /** * @see #append(String, Object, long) @@ -719,8 +720,8 @@ public boolean append(final String key, final Object value) * @throws MemcachedException */ public boolean append(final String key, final Object value, - final long timeout) throws TimeoutException, InterruptedException, - MemcachedException; + final long timeout) + throws TimeoutException, InterruptedException, MemcachedException; /** * Append value to key's data item,this method doesn't wait for reply. @@ -758,8 +759,8 @@ public boolean prepend(final String key, final Object value) * @throws MemcachedException */ public boolean prepend(final String key, final Object value, - final long timeout) throws TimeoutException, InterruptedException, - MemcachedException; + final long timeout) + throws TimeoutException, InterruptedException, MemcachedException; /** * Prepend value to key's data item in memcached.This method doesn't wait @@ -787,8 +788,8 @@ public void prependWithNoReply(final String key, final Object value) * @throws MemcachedException */ public boolean cas(final String key, final int exp, final Object value, - final long cas) throws TimeoutException, InterruptedException, - MemcachedException; + final long cas) + throws TimeoutException, InterruptedException, MemcachedException; /** * Cas is a check and set operation which means "store this data but only if @@ -810,7 +811,7 @@ public boolean cas(final String key, final int exp, final Object value, */ public boolean cas(final String key, final int exp, final T value, final Transcoder transcoder, final long timeout, final long cas) - throws TimeoutException, InterruptedException, MemcachedException; + throws TimeoutException, InterruptedException, MemcachedException; /** * @see #cas(String, int, Object, Transcoder, long, long) @@ -825,8 +826,8 @@ public boolean cas(final String key, final int exp, final T value, * @throws MemcachedException */ public boolean cas(final String key, final int exp, final Object value, - final long timeout, final long cas) throws TimeoutException, - InterruptedException, MemcachedException; + final long timeout, final long cas) + throws TimeoutException, InterruptedException, MemcachedException; /** * @see #cas(String, int, Object, Transcoder, long, long) @@ -843,7 +844,7 @@ public boolean cas(final String key, final int exp, final Object value, */ public boolean cas(final String key, final int exp, final T value, final Transcoder transcoder, final long cas) - throws TimeoutException, InterruptedException, MemcachedException; + throws TimeoutException, InterruptedException, MemcachedException; /** * Cas is a check and set operation which means "store this data but only if @@ -865,7 +866,7 @@ public boolean cas(final String key, final int exp, final T value, */ public boolean cas(final String key, final int exp, final CASOperation operation, final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException; + throws TimeoutException, InterruptedException, MemcachedException; /** * cas is a check and set operation which means "store this data but only if @@ -888,8 +889,8 @@ public boolean cas(final String key, final int exp, */ public boolean cas(final String key, final int exp, GetsResponse getsReponse, final CASOperation operation, - final Transcoder transcoder) throws TimeoutException, - InterruptedException, MemcachedException; + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException; /** * @see #cas(String, int, GetsResponse, CASOperation, Transcoder) @@ -905,7 +906,7 @@ public boolean cas(final String key, final int exp, */ public boolean cas(final String key, final int exp, GetsResponse getsReponse, final CASOperation operation) - throws TimeoutException, InterruptedException, MemcachedException; + throws TimeoutException, InterruptedException, MemcachedException; /** * @see #cas(String, int, GetsResponse, CASOperation, Transcoder) @@ -919,8 +920,8 @@ public boolean cas(final String key, final int exp, * @throws MemcachedException */ public boolean cas(final String key, GetsResponse getsResponse, - final CASOperation operation) throws TimeoutException, - InterruptedException, MemcachedException; + final CASOperation operation) + throws TimeoutException, InterruptedException, MemcachedException; /** * @see #cas(String, int, GetsResponse, CASOperation, Transcoder) @@ -934,8 +935,8 @@ public boolean cas(final String key, GetsResponse getsResponse, * @throws MemcachedException */ public boolean cas(final String key, final int exp, - final CASOperation operation) throws TimeoutException, - InterruptedException, MemcachedException; + final CASOperation operation) + throws TimeoutException, InterruptedException, MemcachedException; /** * @see #cas(String, int, GetsResponse, CASOperation, Transcoder) @@ -963,7 +964,7 @@ public boolean cas(final String key, final CASOperation operation) */ public void casWithNoReply(final String key, GetsResponse getsResponse, final CASOperation operation) - throws TimeoutException, InterruptedException, MemcachedException; + throws TimeoutException, InterruptedException, MemcachedException; /** * cas noreply @@ -979,7 +980,7 @@ public void casWithNoReply(final String key, */ public void casWithNoReply(final String key, final int exp, GetsResponse getsReponse, final CASOperation operation) - throws TimeoutException, InterruptedException, MemcachedException; + throws TimeoutException, InterruptedException, MemcachedException; /** * @see #casWithNoReply(String, int, GetsResponse, CASOperation) @@ -992,8 +993,8 @@ public void casWithNoReply(final String key, final int exp, * @throws MemcachedException */ public void casWithNoReply(final String key, final int exp, - final CASOperation operation) throws TimeoutException, - InterruptedException, MemcachedException; + final CASOperation operation) + throws TimeoutException, InterruptedException, MemcachedException; /** * @see #casWithNoReply(String, int, GetsResponse, CASOperation) @@ -1005,21 +1006,26 @@ public void casWithNoReply(final String key, final int exp, * @throws MemcachedException */ public void casWithNoReply(final String key, - final CASOperation operation) throws TimeoutException, - InterruptedException, MemcachedException; + final CASOperation operation) + throws TimeoutException, InterruptedException, MemcachedException; /** * Delete key's data item from memcached.It it is not exists,return - * false.
time is the amount of time in seconds (or Unix time - * until
which) the client wishes the server to refuse "add" and - * "replace"
commands with this key. For this amount of item, the item - * is put into a
delete queue, which means that it won't possible to - * retrieve it by the
"get" command, but "add" and "replace" command - * with this key will also
fail (the "set" command will succeed, - * however). After the time passes,
the item is finally deleted from - * server memory.
Note: This method is deprecated,because - * memcached 1.4.0 remove the optional argument "time".You can still use - * this method on old version,but is not recommended. + * false.
+ * time is the amount of time in seconds (or Unix time until
+ * which) the client wishes the server to refuse "add" and "replace"
+ * commands with this key. For this amount of item, the item is put into + * a
+ * delete queue, which means that it won't possible to retrieve it by + * the
+ * "get" command, but "add" and "replace" command with this key will + * also
+ * fail (the "set" command will succeed, however). After the time + * passes,
+ * the item is finally deleted from server memory.
+ * Note: This method is deprecated,because memcached 1.4.0 remove + * the optional argument "time".You can still use this method on old + * version,but is not recommended. * * @param key * @param time @@ -1095,8 +1101,8 @@ public boolean touch(final String key, int exp, long opTimeout) * @throws InterruptedException * @throws MemcachedException */ - public boolean touch(final String key, int exp) throws TimeoutException, - InterruptedException, MemcachedException; + public boolean touch(final String key, int exp) + throws TimeoutException, InterruptedException, MemcachedException; /** * Get item and set a new expiration time for it @@ -1219,8 +1225,8 @@ public long incr(final String key, final long delta, final long initValue) * @throws MemcachedException */ public long incr(final String key, final long delta, final long initValue, - long timeout) throws TimeoutException, InterruptedException, - MemcachedException; + long timeout) + throws TimeoutException, InterruptedException, MemcachedException; /** * "decr" are used to change data for some item in-place, decrementing it. @@ -1277,8 +1283,8 @@ public long decr(final String key, final long delta, long initValue) * @throws MemcachedException */ public long decr(final String key, final long delta, long initValue, - long timeout) throws TimeoutException, InterruptedException, - MemcachedException; + long timeout) + throws TimeoutException, InterruptedException, MemcachedException; /** * Make All connected memcached's data item invalid @@ -1287,11 +1293,11 @@ public long decr(final String key, final long delta, long initValue, * @throws InterruptedException * @throws MemcachedException */ - public void flushAll() throws TimeoutException, InterruptedException, - MemcachedException; + public void flushAll() + throws TimeoutException, InterruptedException, MemcachedException; - public void flushAllWithNoReply() throws InterruptedException, - MemcachedException; + public void flushAllWithNoReply() + throws InterruptedException, MemcachedException; /** * Make All connected memcached's data item invalid @@ -1302,8 +1308,8 @@ public void flushAllWithNoReply() throws InterruptedException, * @throws InterruptedException * @throws MemcachedException */ - public void flushAll(long timeout) throws TimeoutException, - InterruptedException, MemcachedException; + public void flushAll(long timeout) + throws TimeoutException, InterruptedException, MemcachedException; /** * Invalidate all existing items immediately @@ -1316,8 +1322,8 @@ public void flushAll(long timeout) throws TimeoutException, * @throws InterruptedException * @throws MemcachedException */ - public void flushAll(InetSocketAddress address) throws MemcachedException, - InterruptedException, TimeoutException; + public void flushAll(InetSocketAddress address) + throws MemcachedException, InterruptedException, TimeoutException; public void flushAllWithNoReply(InetSocketAddress address) throws MemcachedException, InterruptedException; @@ -1336,8 +1342,8 @@ public void flushAll(InetSocketAddress address, long timeout) * @throws MemcachedException */ @Deprecated - public void flushAll(String host) throws TimeoutException, - InterruptedException, MemcachedException; + public void flushAll(String host) + throws TimeoutException, InterruptedException, MemcachedException; public Map stats(InetSocketAddress address) throws MemcachedException, InterruptedException, TimeoutException; @@ -1379,520 +1385,526 @@ public Map> getStats() * @return */ public Map> getStatsByItem( - String itemName) throws MemcachedException, InterruptedException, - TimeoutException;; - - public void shutdown() throws IOException; - - public boolean delete(final String key) throws TimeoutException, - InterruptedException, MemcachedException; - - /** - * return default transcoder,default is SerializingTranscoder - * - * @return - */ - @SuppressWarnings("unchecked") - public Transcoder getTranscoder(); - - /** - * set transcoder - * - * @param transcoder - */ - @SuppressWarnings("unchecked") - public void setTranscoder(final Transcoder transcoder); - - public Map> getStatsByItem( - String itemName, long timeout) throws MemcachedException, - InterruptedException, TimeoutException; - - /** - * get operation timeout setting - * - * @return - */ - public long getOpTimeout(); - - /** - * set operation timeout,default is one second. - * - * @param opTimeout - */ - public void setOpTimeout(long opTimeout); - - public Map getVersions(long timeout) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Returns available memcached servers list.This method is drepcated,please - * use getAvailableServers instead. - * - * @see #getAvailableServers() - * @return - */ - @Deprecated - public Collection getAvaliableServers(); - - /** - * Returns available memcached servers list. - * - * @return A available server collection - */ - public Collection getAvailableServers(); - - /** - * add a memcached server to MemcachedClient - * - * @param server - * @param port - * @param weight - * @throws IOException - */ - public void addServer(final String server, final int port, int weight) - throws IOException; - - public void addServer(final InetSocketAddress inetSocketAddress, int weight) - throws IOException; - - /** - * Delete key's data item from memcached.This method doesn't wait for reply. - * This method does not work on memcached 1.3 or later version.See i s s u e 3
Note: This method is deprecated,because - * memcached 1.4.0 remove the optional argument "time".You can still use - * this method on old version,but is not recommended. - * - * @param key - * @param time - * @throws InterruptedException - * @throws MemcachedException - */ - @Deprecated - public void deleteWithNoReply(final String key, final int time) - throws InterruptedException, MemcachedException; - - public void deleteWithNoReply(final String key) - throws InterruptedException, MemcachedException; - - /** - * "incr" are used to change data for some item in-place, incrementing it. - * The data for the item is treated as decimal representation of a 64-bit - * unsigned integer. If the current data value does not conform to such a - * representation, the commands behave as if the value were 0. Also, the - * item must already exist for incr to work; these commands won't pretend - * that a non-existent key exists with value 0; instead, it will fail.This - * method doesn't wait for reply. - * - * @param key - * @param num - * @throws InterruptedException - * @throws MemcachedException - */ - public void incrWithNoReply(final String key, final long delta) - throws InterruptedException, MemcachedException; - - /** - * "decr" are used to change data for some item in-place, decrementing it. - * The data for the item is treated as decimal representation of a 64-bit - * unsigned integer. If the current data value does not conform to such a - * representation, the commands behave as if the value were 0. Also, the - * item must already exist for decr to work; these commands won't pretend - * that a non-existent key exists with value 0; instead, it will fail.This - * method doesn't wait for reply. - * - * @param key - * @param num - * @throws InterruptedException - * @throws MemcachedException - */ - public void decrWithNoReply(final String key, final long delta) - throws InterruptedException, MemcachedException; - - /** - * Set the verbosity level of the memcached's logging output.This method - * will wait for reply. - * - * @param address - * @param level - * logging level - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public void setLoggingLevelVerbosity(InetSocketAddress address, int level) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Set the verbosity level of the memcached's logging output.This method - * doesn't wait for reply from server - * - * @param address - * memcached server address - * @param level - * logging level - * @throws InterruptedException - * @throws MemcachedException - */ - public void setLoggingLevelVerbosityWithNoReply(InetSocketAddress address, - int level) throws InterruptedException, MemcachedException; - - /** - * Add a memcached client listener - * - * @param listener - */ - public void addStateListener(MemcachedClientStateListener listener); - - /** - * Remove a memcached client listener - * - * @param listener - */ - public void removeStateListener(MemcachedClientStateListener listener); - - /** - * Get all current state listeners - * - * @return - */ - public Collection getStateListeners(); - - public void flushAllWithNoReply(int exptime) throws InterruptedException, - MemcachedException; - - public void flushAll(int exptime, long timeout) throws TimeoutException, - InterruptedException, MemcachedException; - - public void flushAllWithNoReply(InetSocketAddress address, int exptime) - throws MemcachedException, InterruptedException; - - public void flushAll(InetSocketAddress address, long timeout, int exptime) - throws MemcachedException, InterruptedException, TimeoutException; - - /** - * If the memcached dump or network error cause connection closed,xmemcached - * would try to heal the connection.The interval between reconnections is 2 - * seconds by default. You can change that value by this method. - * - * @param healConnectionInterval - * MILLISECONDS - */ - public void setHealSessionInterval(long healConnectionInterval); - - /** - * If the memcached dump or network error cause connection closed,xmemcached - * would try to heal the connection.You can disable this behaviour by using - * this method:
- * client.setEnableHealSession(false);
- * The default value is true. - * - * @param enableHealSession - * @since 1.3.9 - */ - public void setEnableHealSession(boolean enableHealSession); - - /** - * Return the default heal session interval in milliseconds - * - * @return - */ - public long getHealSessionInterval(); - - public Protocol getProtocol(); - - /** - * Store all primitive type as string,defualt is false. - */ - public void setPrimitiveAsString(boolean primitiveAsString); - - /** - * In a high concurrent enviroment,you may want to pool memcached - * clients.But a xmemcached client has to start a reactor thread and some - * thread pools,if you create too many clients,the cost is very large. - * Xmemcached supports connection pool instreadof client pool.you can create - * more connections to one or more memcached servers,and these connections - * share the same reactor and thread pools,it will reduce the cost of - * system. - * - * @param poolSize - * pool size,default is one,every memcached has only one - * connection. - */ - public void setConnectionPoolSize(int poolSize); - - /** - * Whether to enable heart beat - * - * @param enableHeartBeat - * if true,then enable heartbeat,true by default - */ - public void setEnableHeartBeat(boolean enableHeartBeat); - - /** - * Enables/disables sanitizing keys by URLEncoding. - * - * @param sanitizeKey - * if true, then URLEncode all keys - */ - public void setSanitizeKeys(boolean sanitizeKey); - - public boolean isSanitizeKeys(); - - /** - * Get counter for key,and if the key's value is not set,then set it with 0. - * - * @param key - * @return - */ - public Counter getCounter(String key); - - /** - * Get counter for key,and if the key's value is not set,then set it with - * initial value. - * - * @param key - * @param initialValue - * @return - */ - public Counter getCounter(String key, long initialValue); - - /** - * Get key iterator for special memcached server.You must known that the - * iterator is a snapshot for memcached all keys,it is not real-time.The - * 'stats cachedump" has length limitation,so iterator could not visit all - * keys if you have many keys.Your application should not be dependent on - * this feature. - * - * @deprecated memcached 1.6.x will remove cachedump stats command,so this - * method will be removed in the future - * @param address - * @return - */ - @Deprecated - public KeyIterator getKeyIterator(InetSocketAddress address) - throws MemcachedException, InterruptedException, TimeoutException; - - /** - * Configure auth info - * - * @param map - * Auth info map,key is memcached server address,and value is the - * auth info for the key. - */ - public void setAuthInfoMap(Map map); - - /** - * return current all auth info - * - * @return Auth info map,key is memcached server address,and value is the - * auth info for the key. - */ - public Map getAuthInfoMap(); - - /** - * "incr" are used to change data for some item in-place, incrementing it. - * The data for the item is treated as decimal representation of a 64-bit - * unsigned integer. If the current data value does not conform to such a - * representation, the commands behave as if the value were 0. Also, the - * item must already exist for incr to work; these commands won't pretend - * that a non-existent key exists with value 0; instead, it will fail.This - * method doesn't wait for reply. - * - * @param key - * @param delta - * @param initValue - * the initial value to be added when value is not found - * @param timeout - * @param exp - * the initial vlaue expire time, in seconds. Can be up to 30 - * days. After 30 days, is treated as a unix timestamp of an - * exact date. - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - long decr(String key, long delta, long initValue, long timeout, int exp) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * "incr" are used to change data for some item in-place, incrementing it. - * The data for the item is treated as decimal representation of a 64-bit - * unsigned integer. If the current data value does not conform to such a - * representation, the commands behave as if the value were 0. Also, the - * item must already exist for incr to work; these commands won't pretend - * that a non-existent key exists with value 0; instead, it will fail.This - * method doesn't wait for reply. - * - * @param key - * key - * @param delta - * increment delta - * @param initValue - * the initial value to be added when value is not found - * @param timeout - * operation timeout - * @param exp - * the initial vlaue expire time, in seconds. Can be up to 30 - * days. After 30 days, is treated as a unix timestamp of an - * exact date. - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - long incr(String key, long delta, long initValue, long timeout, int exp) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Return the cache instance name - * - * @return - */ - public String getName(); - - /** - * Set cache instance name - * - * @param name - */ - public void setName(String name); - - /** - * Returns reconnecting task queue,the queue is thread-safe and 'weakly - * consistent',but maybe you should not modify it at all. - * - * @return The reconnecting task queue,if the client has not been - * started,returns null. - */ - public Queue getReconnectRequestQueue(); - - /** - * Configure wheather to set client in failure mode.If set it to true,that - * means you want to configure client in failure mode. Failure mode is that - * when a memcached server is down,it would not taken from the server list - * but marked as unavailable,and then further requests to this server will - * be transformed to standby node if configured or throw an exception until - * it comes back up. - * - * @param failureMode - * true is to configure client in failure mode. - */ - public void setFailureMode(boolean failureMode); - - /** - * Returns if client is in failure mode. - * - * @return - */ - public boolean isFailureMode(); - - /** - * Set a key provider for pre-processing keys before sending them to - * memcached. - * - * @since 1.3.8 - * @param keyProvider - */ - public void setKeyProvider(KeyProvider keyProvider); - - /** - * Returns maximum number of timeout exception for closing connection. - * - * @return - */ - public int getTimeoutExceptionThreshold(); - - /** - * Set maximum number of timeout exception for closing connection.You can - * set it to be a large value to disable this feature. - * - * @see #DEFAULT_MAX_TIMEOUTEXCEPTION_THRESHOLD - * @param timeoutExceptionThreshold - */ - public void setTimeoutExceptionThreshold(int timeoutExceptionThreshold); - - /** - * Invalidate all namespace under the namespace using the default operation - * timeout. - * - * @since 1.4.2 - * @param ns - * the namespace - * @throws MemcachedException - * @throws InterruptedException - * @throws TimeoutException - */ - public abstract void invalidateNamespace(String ns) - throws MemcachedException, InterruptedException, TimeoutException; - - /** - * Invalidate all items under the namespace. - * - * @since 1.4.2 - * @param ns - * the namespace - * @param opTimeout - * operation timeout in milliseconds. - * @throws MemcachedException - * @throws InterruptedException - * @throws TimeoutException - */ - public void invalidateNamespace(String ns, long opTimeout) - throws MemcachedException, InterruptedException, TimeoutException; - - /** - * Remove current namespace set for this memcached client.It must begin with - * {@link #beginWithNamespace(String)} method. - * @see #beginWithNamespace(String) - */ - public void endWithNamespace(); - - /** - * set current namespace for following operations with memcached client.It - * must be ended with {@link #endWithNamespace()} method.For example: - *

-			 *    memcachedClient.beginWithNamespace(userId);
-			 *    try{
-			 *      memcachedClient.set("username",0,username);
-			 *      memcachedClient.set("email",0,email);
-			 *    }finally{
-			 *      memcachedClient.endWithNamespace();
-			 *    }
-			 * 
- * @see #endWithNamespace() - * @see #withNamespace(String, MemcachedClientCallable) - * @param ns - */ - public void beginWithNamespace(String ns); - - /** - * With the namespae to do something with current memcached client.All - * operations with memcached client done in callable will be under the - * namespace. {@link #beginWithNamespace(String)} and {@link #endWithNamespace()} will called around automatically. - * For example: - *
-			 *   memcachedClient.withNamespace(userId,new MemcachedClientCallable{
-			 *     public Void call(MemcachedClient client) throws MemcachedException,
-			InterruptedException, TimeoutException{
-			 *      client.set("username",0,username);
-			 *      client.set("email",0,email);
-			 *      return null;
-			 *     }
-			 *   });
-			 *   //invalidate all items under the namespace.
-			 *   memcachedClient.invalidateNamespace(userId);
-			 * 
- * - * @since 1.4.2 - * @param ns - * @param callable - * @see #beginWithNamespace(String) - * @see #endWithNamespace() - * @return - */ - public T withNamespace(String ns, MemcachedClientCallable callable) - throws MemcachedException, InterruptedException, TimeoutException; + String itemName) + throws MemcachedException, InterruptedException, TimeoutException;; + + public void shutdown() throws IOException; + + public boolean delete(final String key) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * return default transcoder,default is SerializingTranscoder + * + * @return + */ + @SuppressWarnings("unchecked") + public Transcoder getTranscoder(); + + /** + * set transcoder + * + * @param transcoder + */ + @SuppressWarnings("unchecked") + public void setTranscoder(final Transcoder transcoder); + + public Map> getStatsByItem( + String itemName, long timeout) + throws MemcachedException, InterruptedException, TimeoutException; + + /** + * get operation timeout setting + * + * @return + */ + public long getOpTimeout(); + + /** + * set operation timeout,default is one second. + * + * @param opTimeout + */ + public void setOpTimeout(long opTimeout); + + public Map getVersions(long timeout) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Returns available memcached servers list.This method is drepcated,please + * use getAvailableServers instead. + * + * @see #getAvailableServers() + * @return + */ + @Deprecated + public Collection getAvaliableServers(); + + /** + * Returns available memcached servers list. + * + * @return A available server collection + */ + public Collection getAvailableServers(); + + /** + * add a memcached server to MemcachedClient + * + * @param server + * @param port + * @param weight + * @throws IOException + */ + public void addServer(final String server, final int port, int weight) + throws IOException; + + public void addServer(final InetSocketAddress inetSocketAddress, int weight) + throws IOException; + + /** + * Delete key's data item from memcached.This method doesn't wait for reply. + * This method does not work on memcached 1.3 or later version.See i s s u e 3
+ * Note: This method is deprecated,because memcached 1.4.0 remove + * the optional argument "time".You can still use this method on old + * version,but is not recommended. + * + * @param key + * @param time + * @throws InterruptedException + * @throws MemcachedException + */ + @Deprecated + public void deleteWithNoReply(final String key, final int time) + throws InterruptedException, MemcachedException; + + public void deleteWithNoReply(final String key) + throws InterruptedException, MemcachedException; + + /** + * "incr" are used to change data for some item in-place, incrementing it. + * The data for the item is treated as decimal representation of a 64-bit + * unsigned integer. If the current data value does not conform to such a + * representation, the commands behave as if the value were 0. Also, the + * item must already exist for incr to work; these commands won't pretend + * that a non-existent key exists with value 0; instead, it will fail.This + * method doesn't wait for reply. + * + * @param key + * @param num + * @throws InterruptedException + * @throws MemcachedException + */ + public void incrWithNoReply(final String key, final long delta) + throws InterruptedException, MemcachedException; + + /** + * "decr" are used to change data for some item in-place, decrementing it. + * The data for the item is treated as decimal representation of a 64-bit + * unsigned integer. If the current data value does not conform to such a + * representation, the commands behave as if the value were 0. Also, the + * item must already exist for decr to work; these commands won't pretend + * that a non-existent key exists with value 0; instead, it will fail.This + * method doesn't wait for reply. + * + * @param key + * @param num + * @throws InterruptedException + * @throws MemcachedException + */ + public void decrWithNoReply(final String key, final long delta) + throws InterruptedException, MemcachedException; + + /** + * Set the verbosity level of the memcached's logging output.This method + * will wait for reply. + * + * @param address + * @param level + * logging level + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public void setLoggingLevelVerbosity(InetSocketAddress address, int level) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Set the verbosity level of the memcached's logging output.This method + * doesn't wait for reply from server + * + * @param address + * memcached server address + * @param level + * logging level + * @throws InterruptedException + * @throws MemcachedException + */ + public void setLoggingLevelVerbosityWithNoReply(InetSocketAddress address, + int level) throws InterruptedException, MemcachedException; + + /** + * Add a memcached client listener + * + * @param listener + */ + public void addStateListener(MemcachedClientStateListener listener); + + /** + * Remove a memcached client listener + * + * @param listener + */ + public void removeStateListener(MemcachedClientStateListener listener); + + /** + * Get all current state listeners + * + * @return + */ + public Collection getStateListeners(); + + public void flushAllWithNoReply(int exptime) + throws InterruptedException, MemcachedException; + + public void flushAll(int exptime, long timeout) + throws TimeoutException, InterruptedException, MemcachedException; + + public void flushAllWithNoReply(InetSocketAddress address, int exptime) + throws MemcachedException, InterruptedException; + + public void flushAll(InetSocketAddress address, long timeout, int exptime) + throws MemcachedException, InterruptedException, TimeoutException; + + /** + * If the memcached dump or network error cause connection closed,xmemcached + * would try to heal the connection.The interval between reconnections is 2 + * seconds by default. You can change that value by this method. + * + * @param healConnectionInterval + * MILLISECONDS + */ + public void setHealSessionInterval(long healConnectionInterval); + + /** + * If the memcached dump or network error cause connection closed,xmemcached + * would try to heal the connection.You can disable this behaviour by using + * this method:
+ * client.setEnableHealSession(false);
+ * The default value is true. + * + * @param enableHealSession + * @since 1.3.9 + */ + public void setEnableHealSession(boolean enableHealSession); + + /** + * Return the default heal session interval in milliseconds + * + * @return + */ + public long getHealSessionInterval(); + + public Protocol getProtocol(); + + /** + * Store all primitive type as string,defualt is false. + */ + public void setPrimitiveAsString(boolean primitiveAsString); + + /** + * In a high concurrent enviroment,you may want to pool memcached + * clients.But a xmemcached client has to start a reactor thread and some + * thread pools,if you create too many clients,the cost is very large. + * Xmemcached supports connection pool instreadof client pool.you can create + * more connections to one or more memcached servers,and these connections + * share the same reactor and thread pools,it will reduce the cost of + * system. + * + * @param poolSize + * pool size,default is one,every memcached has only one + * connection. + */ + public void setConnectionPoolSize(int poolSize); + + /** + * Whether to enable heart beat + * + * @param enableHeartBeat + * if true,then enable heartbeat,true by default + */ + public void setEnableHeartBeat(boolean enableHeartBeat); + + /** + * Enables/disables sanitizing keys by URLEncoding. + * + * @param sanitizeKey + * if true, then URLEncode all keys + */ + public void setSanitizeKeys(boolean sanitizeKey); + + public boolean isSanitizeKeys(); + + /** + * Get counter for key,and if the key's value is not set,then set it with 0. + * + * @param key + * @return + */ + public Counter getCounter(String key); + + /** + * Get counter for key,and if the key's value is not set,then set it with + * initial value. + * + * @param key + * @param initialValue + * @return + */ + public Counter getCounter(String key, long initialValue); + + /** + * Get key iterator for special memcached server.You must known that the + * iterator is a snapshot for memcached all keys,it is not real-time.The + * 'stats cachedump" has length limitation,so iterator could not visit all + * keys if you have many keys.Your application should not be dependent on + * this feature. + * + * @deprecated memcached 1.6.x will remove cachedump stats command,so this + * method will be removed in the future + * @param address + * @return + */ + @Deprecated + public KeyIterator getKeyIterator(InetSocketAddress address) + throws MemcachedException, InterruptedException, TimeoutException; + + /** + * Configure auth info + * + * @param map + * Auth info map,key is memcached server address,and value is the + * auth info for the key. + */ + public void setAuthInfoMap(Map map); + + /** + * return current all auth info + * + * @return Auth info map,key is memcached server address,and value is the + * auth info for the key. + */ + public Map getAuthInfoMap(); + + /** + * "incr" are used to change data for some item in-place, incrementing it. + * The data for the item is treated as decimal representation of a 64-bit + * unsigned integer. If the current data value does not conform to such a + * representation, the commands behave as if the value were 0. Also, the + * item must already exist for incr to work; these commands won't pretend + * that a non-existent key exists with value 0; instead, it will fail.This + * method doesn't wait for reply. + * + * @param key + * @param delta + * @param initValue + * the initial value to be added when value is not found + * @param timeout + * @param exp + * the initial vlaue expire time, in seconds. Can be up to 30 + * days. After 30 days, is treated as a unix timestamp of an + * exact date. + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + long decr(String key, long delta, long initValue, long timeout, int exp) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * "incr" are used to change data for some item in-place, incrementing it. + * The data for the item is treated as decimal representation of a 64-bit + * unsigned integer. If the current data value does not conform to such a + * representation, the commands behave as if the value were 0. Also, the + * item must already exist for incr to work; these commands won't pretend + * that a non-existent key exists with value 0; instead, it will fail.This + * method doesn't wait for reply. + * + * @param key + * key + * @param delta + * increment delta + * @param initValue + * the initial value to be added when value is not found + * @param timeout + * operation timeout + * @param exp + * the initial vlaue expire time, in seconds. Can be up to 30 + * days. After 30 days, is treated as a unix timestamp of an + * exact date. + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + long incr(String key, long delta, long initValue, long timeout, int exp) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Return the cache instance name + * + * @return + */ + public String getName(); + + /** + * Set cache instance name + * + * @param name + */ + public void setName(String name); + + /** + * Returns reconnecting task queue,the queue is thread-safe and 'weakly + * consistent',but maybe you should not modify it at all. + * + * @return The reconnecting task queue,if the client has not been + * started,returns null. + */ + public Queue getReconnectRequestQueue(); + + /** + * Configure wheather to set client in failure mode.If set it to true,that + * means you want to configure client in failure mode. Failure mode is that + * when a memcached server is down,it would not taken from the server list + * but marked as unavailable,and then further requests to this server will + * be transformed to standby node if configured or throw an exception until + * it comes back up. + * + * @param failureMode + * true is to configure client in failure mode. + */ + public void setFailureMode(boolean failureMode); + + /** + * Returns if client is in failure mode. + * + * @return + */ + public boolean isFailureMode(); + + /** + * Set a key provider for pre-processing keys before sending them to + * memcached. + * + * @since 1.3.8 + * @param keyProvider + */ + public void setKeyProvider(KeyProvider keyProvider); + + /** + * Returns maximum number of timeout exception for closing connection. + * + * @return + */ + public int getTimeoutExceptionThreshold(); + + /** + * Set maximum number of timeout exception for closing connection.You can + * set it to be a large value to disable this feature. + * + * @see #DEFAULT_MAX_TIMEOUTEXCEPTION_THRESHOLD + * @param timeoutExceptionThreshold + */ + public void setTimeoutExceptionThreshold(int timeoutExceptionThreshold); + + /** + * Invalidate all namespace under the namespace using the default operation + * timeout. + * + * @since 1.4.2 + * @param ns + * the namespace + * @throws MemcachedException + * @throws InterruptedException + * @throws TimeoutException + */ + public abstract void invalidateNamespace(String ns) + throws MemcachedException, InterruptedException, TimeoutException; + + /** + * Invalidate all items under the namespace. + * + * @since 1.4.2 + * @param ns + * the namespace + * @param opTimeout + * operation timeout in milliseconds. + * @throws MemcachedException + * @throws InterruptedException + * @throws TimeoutException + */ + public void invalidateNamespace(String ns, long opTimeout) + throws MemcachedException, InterruptedException, TimeoutException; + + /** + * Remove current namespace set for this memcached client.It must begin with + * {@link #beginWithNamespace(String)} method. + * + * @see #beginWithNamespace(String) + */ + public void endWithNamespace(); + + /** + * set current namespace for following operations with memcached client.It + * must be ended with {@link #endWithNamespace()} method.For example: + * + *
+	 * memcachedClient.beginWithNamespace(userId);
+	 * try {
+	 * 	memcachedClient.set("username", 0, username);
+	 * 	memcachedClient.set("email", 0, email);
+	 * } finally {
+	 * 	memcachedClient.endWithNamespace();
+	 * }
+	 * 
+ * + * @see #endWithNamespace() + * @see #withNamespace(String, MemcachedClientCallable) + * @param ns + */ + public void beginWithNamespace(String ns); + + /** + * With the namespae to do something with current memcached client.All + * operations with memcached client done in callable will be under the + * namespace. {@link #beginWithNamespace(String)} and + * {@link #endWithNamespace()} will called around automatically. For + * example: + * + *
+	 *   memcachedClient.withNamespace(userId,new MemcachedClientCallable{
+	 *     public Void call(MemcachedClient client) throws MemcachedException,
+	InterruptedException, TimeoutException{
+	 *      client.set("username",0,username);
+	 *      client.set("email",0,email);
+	 *      return null;
+	 *     }
+	 *   });
+	 *   //invalidate all items under the namespace.
+	 *   memcachedClient.invalidateNamespace(userId);
+	 * 
+ * + * @since 1.4.2 + * @param ns + * @param callable + * @see #beginWithNamespace(String) + * @see #endWithNamespace() + * @return + */ + public T withNamespace(String ns, MemcachedClientCallable callable) + throws MemcachedException, InterruptedException, TimeoutException; } \ No newline at end of file diff --git a/src/main/java/net/rubyeye/xmemcached/MemcachedClientBuilder.java b/src/main/java/net/rubyeye/xmemcached/MemcachedClientBuilder.java index 6cc1fae36..8ee6d5007 100644 --- a/src/main/java/net/rubyeye/xmemcached/MemcachedClientBuilder.java +++ b/src/main/java/net/rubyeye/xmemcached/MemcachedClientBuilder.java @@ -254,7 +254,7 @@ public void setStateListeners( * @since 1.3.8 */ public void setMaxQueuedNoReplyOperations(int maxQueuedNoReplyOperations); - + /** * If the memcached dump or network error cause connection closed,xmemcached * would try to heal the connection.The interval between reconnections is 2 @@ -280,13 +280,16 @@ public void setStateListeners( /** * Set default operation timeout. - * @param opTimeout Operation timeout value in milliseconds. + * + * @param opTimeout + * Operation timeout value in milliseconds. * @since 1.4.1 */ public void setOpTimeout(long opTimeout); /** * Returns the default operation timeout in milliseconds. + * * @since 1.4.1 * @return */ diff --git a/src/main/java/net/rubyeye/xmemcached/MemcachedClientCallable.java b/src/main/java/net/rubyeye/xmemcached/MemcachedClientCallable.java index 95e06b7d4..610464f14 100644 --- a/src/main/java/net/rubyeye/xmemcached/MemcachedClientCallable.java +++ b/src/main/java/net/rubyeye/xmemcached/MemcachedClientCallable.java @@ -26,6 +26,6 @@ * @param */ public interface MemcachedClientCallable { - public T call(MemcachedClient client) throws MemcachedException, - InterruptedException, TimeoutException; + public T call(MemcachedClient client) + throws MemcachedException, InterruptedException, TimeoutException; } diff --git a/src/main/java/net/rubyeye/xmemcached/MemcachedClientStateListener.java b/src/main/java/net/rubyeye/xmemcached/MemcachedClientStateListener.java index 22b92b881..6a1b24b03 100644 --- a/src/main/java/net/rubyeye/xmemcached/MemcachedClientStateListener.java +++ b/src/main/java/net/rubyeye/xmemcached/MemcachedClientStateListener.java @@ -63,5 +63,6 @@ public void onDisconnected(MemcachedClient memcachedClient, * @param memcachedClient * @param throwable */ - public void onException(MemcachedClient memcachedClient, Throwable throwable); + public void onException(MemcachedClient memcachedClient, + Throwable throwable); } diff --git a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java index 20676bbba..a9f6dc2c3 100644 --- a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java +++ b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java @@ -81,7 +81,10 @@ * @author dennis(killme2008@gmail.com) * */ -public class XMemcachedClient implements XMemcachedClientMBean, MemcachedClient { +public class XMemcachedClient + implements + XMemcachedClientMBean, + MemcachedClient { private static final Logger log = LoggerFactory .getLogger(XMemcachedClient.class); @@ -143,7 +146,8 @@ public void setTimeoutExceptionThreshold(int timeoutExceptionThreshold) { + timeoutExceptionThreshold); } if (timeoutExceptionThreshold < 100) { - log.warn("Too small timeoutExceptionThreshold value may cause connections disconnect/reconnect frequently."); + log.warn( + "Too small timeoutExceptionThreshold value may cause connections disconnect/reconnect frequently."); } this.timeoutExceptionThreshold = timeoutExceptionThreshold; } @@ -247,8 +251,8 @@ public final void setOpTimeout(long opTimeout) { public void setHealSessionInterval(long healConnectionInterval) { if (healConnectionInterval <= 0) { - throw new IllegalArgumentException("Invalid heal session interval:" - + healConnectionInterval); + throw new IllegalArgumentException( + "Invalid heal session interval:" + healConnectionInterval); } if (null != this.connector) { this.connector.setHealSessionInterval(healConnectionInterval); @@ -287,7 +291,8 @@ public final Connector getConnector() { * @see * net.rubyeye.xmemcached.MemcachedClient#setOptimizeMergeBuffer(boolean) */ - public final void setOptimizeMergeBuffer(final boolean optimizeMergeBuffer) { + public final void setOptimizeMergeBuffer( + final boolean optimizeMergeBuffer) { this.connector.setOptimizeMergeBuffer(optimizeMergeBuffer); } @@ -355,8 +360,9 @@ public XMemcachedClient(final String host, final int port, int weight) XMemcachedClientBuilder.getDefaultSocketOptions(), new TextCommandFactory(), new SerializingTranscoder()); this.start0(); - this.connect(new InetSocketAddressWrapper(this.newSocketAddress(host, - port), this.serverOrderCount.incrementAndGet(), weight, null)); + this.connect( + new InetSocketAddressWrapper(this.newSocketAddress(host, port), + this.serverOrderCount.incrementAndGet(), weight, null)); } protected InetSocketAddress newSocketAddress(final String server, @@ -398,16 +404,16 @@ public final void addServer(final String server, final int port, int weight) throw new IllegalArgumentException("weight<=0"); } this.checkServerPort(server, port); - this.connect(new InetSocketAddressWrapper(this.newSocketAddress(server, - port), this.serverOrderCount.incrementAndGet(), weight, null)); + this.connect(new InetSocketAddressWrapper( + this.newSocketAddress(server, port), + this.serverOrderCount.incrementAndGet(), weight, null)); } /* * (non-Javadoc) * - * @see - * net.rubyeye.xmemcached.MemcachedClient#addServer(java.net.InetSocketAddress - * ) + * @see net.rubyeye.xmemcached.MemcachedClient#addServer(java.net. + * InetSocketAddress ) */ public final void addServer(final InetSocketAddress inetSocketAddress) throws IOException { @@ -551,8 +557,8 @@ protected void removeAddr(InetSocketAddress address) { if (standBySession != null) { for (Session session : standBySession) { if (session != null) { - this.connector.removeReconnectRequest(session - .getRemoteSocketAddress()); + this.connector.removeReconnectRequest( + session.getRemoteSocketAddress()); // Disable auto reconnection ((MemcachedSession) session).setAllowReconnect(false); // Close connection @@ -570,7 +576,8 @@ protected void connect( InetSocketAddress inetSocketAddress = inetSocketAddressWrapper .getInetSocketAddress(); if (this.connectionPoolSize > 1) { - log.warn("You are using connection pool for xmemcached client,it's not recommended unless you have test it that it can boost performance in your app."); + log.warn( + "You are using connection pool for xmemcached client,it's not recommended unless you have test it that it can boost performance in your app."); } for (int i = 0; i < this.connectionPoolSize; i++) { Future future = null; @@ -581,8 +588,8 @@ protected void connect( if (!future.get(this.connectTimeout, TimeUnit.MILLISECONDS)) { log.error("connect to " - + SystemUtils.getRawAddress(inetSocketAddress) - + ":" + inetSocketAddress.getPort() + " fail"); + + SystemUtils.getRawAddress(inetSocketAddress) + ":" + + inetSocketAddress.getPort() + " fail"); } else { connected = true; } @@ -597,11 +604,9 @@ protected void connect( e); } catch (TimeoutException e) { throwable = e; - log.error( - "connect to " - + SystemUtils.getRawAddress(inetSocketAddress) - + ":" + inetSocketAddress.getPort() - + " timeout", e); + log.error("connect to " + + SystemUtils.getRawAddress(inetSocketAddress) + ":" + + inetSocketAddress.getPort() + " timeout", e); } catch (Exception e) { throwable = e; log.error( @@ -621,9 +626,9 @@ protected void connect( this.connector.addSession(new ClosedMemcachedTCPSession( inetSocketAddressWrapper)); } - this.connector.addToWatingQueue(new ReconnectRequest( - inetSocketAddressWrapper, 0, this - .getHealSessionInterval())); + this.connector.addToWatingQueue( + new ReconnectRequest(inetSocketAddressWrapper, 0, + this.getHealSessionInterval())); log.error( "Connect to " + SystemUtils.getRawAddress(inetSocketAddress) @@ -637,8 +642,8 @@ protected void connect( @SuppressWarnings("unchecked") private final Object fetch0(final String key, final byte[] keyBytes, final CommandType cmdType, final long timeout, - Transcoder transcoder) throws InterruptedException, - TimeoutException, MemcachedException { + Transcoder transcoder) + throws InterruptedException, TimeoutException, MemcachedException { final Command command = this.commandFactory.createGetCommand(key, keyBytes, cmdType, this.transcoder); this.latchWait(command, timeout, this.sendCommand(command)); @@ -761,8 +766,7 @@ protected MemcachedConnector newConnector(BufferAllocator bufferAllocator, private final void registerMBean() { if (this.shutdown) { - XMemcachedMbeanServer.getInstance().registMBean( - this, + XMemcachedMbeanServer.getInstance().registMBean(this, this.getClass().getPackage().getName() + ":type=" + this.getClass().getSimpleName() + "-" + MemcachedClientNameHolder.getName()); @@ -780,7 +784,8 @@ public void setOptimizeGet(boolean optimizeGet) { * net.rubyeye.xmemcached.MemcachedClient#setBufferAllocator(net.rubyeye * .xmemcached.buffer.BufferAllocator) */ - public final void setBufferAllocator(final BufferAllocator bufferAllocator) { + public final void setBufferAllocator( + final BufferAllocator bufferAllocator) { this.connector.setBufferAllocator(bufferAllocator); } @@ -835,8 +840,10 @@ public XMemcachedClient() throws IOException { } /** - * XMemcachedClient constructor.Every server's weight is one by default. - * You should not new client instance by this method, use MemcachedClientBuilder instead. + * XMemcachedClient constructor.Every server's weight is one by default. You + * should not new client instance by this method, use MemcachedClientBuilder + * instead. + * * @param locator * @param allocator * @param conf @@ -860,8 +867,8 @@ public XMemcachedClient(MemcachedSessionLocator locator, this.setConnectTimeout(connectTimeout); this.setFailureMode(failureMode); this.setName(name); - this.optimiezeSetReadThreadCount(conf, addressMap == null ? 0 - : addressMap.size()); + this.optimiezeSetReadThreadCount(conf, + addressMap == null ? 0 : addressMap.size()); this.buildConnector(locator, allocator, conf, socketOptions, commandFactory, transcoder); if (stateListeners != null) { @@ -903,12 +910,11 @@ public XMemcachedClient(MemcachedSessionLocator locator, * @throws IOException */ @SuppressWarnings("unchecked") - XMemcachedClient(MemcachedSessionLocator locator, - BufferAllocator allocator, Configuration conf, - Map socketOptions, + XMemcachedClient(MemcachedSessionLocator locator, BufferAllocator allocator, + Configuration conf, Map socketOptions, CommandFactory commandFactory, Transcoder transcoder, - Map addressMap, - int[] weights, List stateListeners, + Map addressMap, int[] weights, + List stateListeners, Map infoMap, int poolSize, long connectTimeout, final String name, boolean failureMode) throws IOException { @@ -935,8 +941,8 @@ public XMemcachedClient(MemcachedSessionLocator locator, throw new IllegalArgumentException( "weights.length is less than addressList.size()"); } - this.optimiezeSetReadThreadCount(conf, addressMap == null ? 0 - : addressMap.size()); + this.optimiezeSetReadThreadCount(conf, + addressMap == null ? 0 : addressMap.size()); this.buildConnector(locator, allocator, conf, socketOptions, commandFactory, transcoder); if (stateListeners != null) { @@ -958,8 +964,8 @@ public XMemcachedClient(MemcachedSessionLocator locator, null)); if (standbyNodeAddr != null) { this.connect(new InetSocketAddressWrapper(standbyNodeAddr, - this.serverOrderCount.incrementAndGet(), - weights[i], mainNodeAddr)); + this.serverOrderCount.incrementAndGet(), weights[i], + mainNodeAddr)); } i++; } @@ -972,7 +978,8 @@ private final void optimiezeSetReadThreadCount(Configuration conf, if (!this.isWindowsPlatform() && conf.getReadThreadCount() == DEFAULT_READ_THREAD_COUNT) { int threadCount = SystemUtils.getSystemThreadCount(); - conf.setReadThreadCount(addressCount > threadCount ? threadCount + conf.setReadThreadCount(addressCount > threadCount + ? threadCount : addressCount); } } @@ -1038,8 +1045,8 @@ public XMemcachedClient(List addressList, */ @SuppressWarnings("unchecked") public final T get(final String key, final long timeout, - final Transcoder transcoder) throws TimeoutException, - InterruptedException, MemcachedException { + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException { return (T) this.get0(key, timeout, CommandType.GET_ONE, transcoder); } @@ -1071,8 +1078,8 @@ public final T get(final String key, final Transcoder transcoder) * @see net.rubyeye.xmemcached.MemcachedClient#get(java.lang.String) */ @SuppressWarnings("unchecked") - public final T get(final String key) throws TimeoutException, - InterruptedException, MemcachedException { + public final T get(final String key) + throws TimeoutException, InterruptedException, MemcachedException { return (T) this.get(key, this.opTimeout); } @@ -1093,8 +1100,8 @@ private Object get0(String key, final long timeout, */ @SuppressWarnings("unchecked") public final GetsResponse gets(final String key, final long timeout, - final Transcoder transcoder) throws TimeoutException, - InterruptedException, MemcachedException { + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException { return (GetsResponse) this.get0(key, timeout, CommandType.GETS_ONE, transcoder); } @@ -1128,8 +1135,8 @@ public final GetsResponse gets(final String key, final long timeout) */ @SuppressWarnings("unchecked") public final GetsResponse gets(final String key, - final Transcoder transcoder) throws TimeoutException, - InterruptedException, MemcachedException { + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException { return this.gets(key, this.opTimeout, transcoder); } @@ -1139,10 +1146,9 @@ public final GetsResponse gets(final String key, * @see net.rubyeye.xmemcached.MemcachedClient#get(java.util.Collection, * long, net.rubyeye.xmemcached.transcoders.Transcoder) */ - public final Map get( - final Collection keyCollections, final long timeout, - final Transcoder transcoder) throws TimeoutException, - InterruptedException, MemcachedException { + public final Map get(final Collection keyCollections, + final long timeout, final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException { return this.getMulti0(keyCollections, timeout, CommandType.GET_MANY, transcoder); } @@ -1153,10 +1159,9 @@ public final Map get( * @see net.rubyeye.xmemcached.MemcachedClient#get(java.util.Collection, * net.rubyeye.xmemcached.transcoders.Transcoder) */ - public final Map get( - final Collection keyCollections, - final Transcoder transcoder) throws TimeoutException, - InterruptedException, MemcachedException { + public final Map get(final Collection keyCollections, + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException { return this.getMulti0(keyCollections, this.opTimeout, CommandType.GET_MANY, transcoder); } @@ -1178,8 +1183,8 @@ public final Map get(final Collection keyCollections) * long) */ @SuppressWarnings("unchecked") - public final Map get( - final Collection keyCollections, final long timeout) + public final Map get(final Collection keyCollections, + final long timeout) throws TimeoutException, InterruptedException, MemcachedException { return this.get(keyCollections, timeout, this.transcoder); } @@ -1193,8 +1198,8 @@ public final Map get( @SuppressWarnings("unchecked") public final Map> gets( final Collection keyCollections, final long timeout, - final Transcoder transcoder) throws TimeoutException, - InterruptedException, MemcachedException { + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException { return (Map>) this.getMulti0(keyCollections, timeout, CommandType.GETS_MANY, transcoder); } @@ -1205,8 +1210,8 @@ public final Map> gets( * @see net.rubyeye.xmemcached.MemcachedClient#gets(java.util.Collection) */ public final Map> gets( - final Collection keyCollections) throws TimeoutException, - InterruptedException, MemcachedException { + final Collection keyCollections) + throws TimeoutException, InterruptedException, MemcachedException { return this.gets(keyCollections, this.opTimeout); } @@ -1231,15 +1236,15 @@ public final Map> gets( */ public final Map> gets( final Collection keyCollections, - final Transcoder transcoder) throws TimeoutException, - InterruptedException, MemcachedException { + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException { return this.gets(keyCollections, this.opTimeout, transcoder); } private final Map getMulti0(final Collection keys, final long timeout, final CommandType cmdType, - final Transcoder transcoder) throws TimeoutException, - InterruptedException, MemcachedException { + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException { if (keys == null || keys.size() == 0) { return null; } @@ -1301,9 +1306,9 @@ private Map reduceResult(final CommandType cmdType, .iterator(); while (it.hasNext()) { Map.Entry entry = it.next(); - GetsResponse getsResponse = new GetsResponse(entry - .getValue().getCas(), transcoder.decode(entry - .getValue())); + GetsResponse getsResponse = new GetsResponse( + entry.getValue().getCas(), + transcoder.decode(entry.getValue())); String decodeKey = this.decodeKey(entry.getKey()); if (decodeKey != null) { result.put(decodeKey, (T) getsResponse); @@ -1340,9 +1345,9 @@ private final Collection> catalogKeys( return catalogKeys; } - private final Command sendGetMultiCommand( - final Collection keys, final CountDownLatch latch, - final CommandType cmdType, final Transcoder transcoder) + private final Command sendGetMultiCommand(final Collection keys, + final CountDownLatch latch, final CommandType cmdType, + final Transcoder transcoder) throws InterruptedException, TimeoutException, MemcachedException { final Command command = this.commandFactory.createGetMultiCommand(keys, latch, cmdType, transcoder); @@ -1372,8 +1377,8 @@ public void setWithNoReply(String key, int exp, Object value) } public void setWithNoReply(String key, int exp, T value, - Transcoder transcoder) throws InterruptedException, - MemcachedException { + Transcoder transcoder) + throws InterruptedException, MemcachedException { key = this.preProcessKey(key); byte[] keyBytes = this.checkStoreArguments(key, exp, value); try { @@ -1404,7 +1409,8 @@ private final byte[] checkStoreArguments(final String key, * @see net.rubyeye.xmemcached.MemcachedClient#set(java.lang.String, int, * java.lang.Object) */ - public final boolean set(final String key, final int exp, final Object value) + public final boolean set(final String key, final int exp, + final Object value) throws TimeoutException, InterruptedException, MemcachedException { return this.set(key, exp, value, this.opTimeout); } @@ -1417,8 +1423,8 @@ public final boolean set(final String key, final int exp, final Object value) */ @SuppressWarnings("unchecked") public final boolean set(final String key, final int exp, - final Object value, final long timeout) throws TimeoutException, - InterruptedException, MemcachedException { + final Object value, final long timeout) + throws TimeoutException, InterruptedException, MemcachedException { return this.set(key, exp, value, this.transcoder, timeout); } @@ -1428,8 +1434,8 @@ public final boolean set(final String key, final int exp, * @see net.rubyeye.xmemcached.MemcachedClient#set(java.lang.String, int, T, * net.rubyeye.xmemcached.transcoders.Transcoder) */ - public final boolean set(final String key, final int exp, - final T value, final Transcoder transcoder) + public final boolean set(final String key, final int exp, final T value, + final Transcoder transcoder) throws TimeoutException, InterruptedException, MemcachedException { return this.set(key, exp, value, transcoder, this.opTimeout); } @@ -1461,7 +1467,8 @@ private boolean add0(String key, int exp, T value, * @see net.rubyeye.xmemcached.MemcachedClient#add(java.lang.String, int, * java.lang.Object) */ - public final boolean add(final String key, final int exp, final Object value) + public final boolean add(final String key, final int exp, + final Object value) throws TimeoutException, InterruptedException, MemcachedException { return this.add(key, exp, value, this.opTimeout); } @@ -1474,8 +1481,8 @@ public final boolean add(final String key, final int exp, final Object value) */ @SuppressWarnings("unchecked") public final boolean add(final String key, final int exp, - final Object value, final long timeout) throws TimeoutException, - InterruptedException, MemcachedException { + final Object value, final long timeout) + throws TimeoutException, InterruptedException, MemcachedException { return this.add(key, exp, value, this.transcoder, timeout); } @@ -1485,8 +1492,8 @@ public final boolean add(final String key, final int exp, * @see net.rubyeye.xmemcached.MemcachedClient#add(java.lang.String, int, T, * net.rubyeye.xmemcached.transcoders.Transcoder) */ - public final boolean add(final String key, final int exp, - final T value, final Transcoder transcoder) + public final boolean add(final String key, final int exp, final T value, + final Transcoder transcoder) throws TimeoutException, InterruptedException, MemcachedException { return this.add(key, exp, value, transcoder, this.opTimeout); } @@ -1499,8 +1506,8 @@ public void addWithNoReply(String key, int exp, Object value) } public void addWithNoReply(String key, int exp, T value, - Transcoder transcoder) throws InterruptedException, - MemcachedException { + Transcoder transcoder) + throws InterruptedException, MemcachedException { key = this.preProcessKey(key); byte[] keyBytes = this.checkStoreArguments(key, exp, value); try { @@ -1520,8 +1527,8 @@ public void replaceWithNoReply(String key, int exp, Object value) } public void replaceWithNoReply(String key, int exp, T value, - Transcoder transcoder) throws InterruptedException, - MemcachedException { + Transcoder transcoder) + throws InterruptedException, MemcachedException { key = this.preProcessKey(key); byte[] keyBytes = this.checkStoreArguments(key, exp, value); try { @@ -1555,8 +1562,8 @@ public final boolean replace(String key, final int exp, final T value, * int, java.lang.Object) */ public final boolean replace(final String key, final int exp, - final Object value) throws TimeoutException, InterruptedException, - MemcachedException { + final Object value) + throws TimeoutException, InterruptedException, MemcachedException { return this.replace(key, exp, value, this.opTimeout); } @@ -1568,8 +1575,8 @@ public final boolean replace(final String key, final int exp, */ @SuppressWarnings("unchecked") public final boolean replace(final String key, final int exp, - final Object value, final long timeout) throws TimeoutException, - InterruptedException, MemcachedException { + final Object value, final long timeout) + throws TimeoutException, InterruptedException, MemcachedException { return this.replace(key, exp, value, this.transcoder, timeout); } @@ -1603,8 +1610,8 @@ public final boolean append(final String key, final Object value) * java.lang.Object, long) */ public final boolean append(String key, final Object value, - final long timeout) throws TimeoutException, InterruptedException, - MemcachedException { + final long timeout) + throws TimeoutException, InterruptedException, MemcachedException { key = this.preProcessKey(key); byte[] keyBytes = this.checkStoreArguments(key, 0, value); return this.sendStoreCommand(this.commandFactory.createAppendCommand( @@ -1642,8 +1649,8 @@ public final boolean prepend(final String key, final Object value) * java.lang.Object, long) */ public final boolean prepend(String key, final Object value, - final long timeout) throws TimeoutException, InterruptedException, - MemcachedException { + final long timeout) + throws TimeoutException, InterruptedException, MemcachedException { key = this.preProcessKey(key); byte[] keyBytes = this.checkStoreArguments(key, 0, value); return this.sendStoreCommand(this.commandFactory.createPrependCommand( @@ -1669,8 +1676,8 @@ public void prependWithNoReply(String key, Object value) * java.lang.Object, long) */ public final boolean cas(final String key, final int exp, - final Object value, final long cas) throws TimeoutException, - InterruptedException, MemcachedException { + final Object value, final long cas) + throws TimeoutException, InterruptedException, MemcachedException { return this.cas(key, exp, value, this.opTimeout, cas); } @@ -1708,8 +1715,8 @@ public final boolean cas(final String key, final int exp, * @see net.rubyeye.xmemcached.MemcachedClient#cas(java.lang.String, int, T, * net.rubyeye.xmemcached.transcoders.Transcoder, long) */ - public final boolean cas(final String key, final int exp, - final T value, final Transcoder transcoder, final long cas) + public final boolean cas(final String key, final int exp, final T value, + final Transcoder transcoder, final long cas) throws TimeoutException, InterruptedException, MemcachedException { return this.cas(key, exp, value, transcoder, this.opTimeout, cas); } @@ -1719,7 +1726,8 @@ private final boolean cas0(final String key, final int exp, final Transcoder transcoder, byte[] keyBytes, boolean noreply) throws TimeoutException, InterruptedException, MemcachedException { if (operation == null) { - throw new IllegalArgumentException("CASOperation could not be null"); + throw new IllegalArgumentException( + "CASOperation could not be null"); } if (operation.getMaxTries() < 0) { throw new IllegalArgumentException( @@ -1731,19 +1739,20 @@ private final boolean cas0(final String key, final int exp, throw new NoValueException("Null GetsResponse for key=" + key); } while (tryCount <= operation.getMaxTries() - && result != null - && !this.sendStoreCommand(this.commandFactory.createCASCommand( - key, - keyBytes, - exp, - operation.getNewValue(result.getCas(), - result.getValue()), result.getCas(), noreply, - transcoder), this.opTimeout) && !noreply) { + && result != null && !this + .sendStoreCommand( + this.commandFactory.createCASCommand(key, + keyBytes, exp, + operation.getNewValue(result.getCas(), + result.getValue()), + result.getCas(), noreply, transcoder), + this.opTimeout) + && !noreply) { tryCount++; result = this.gets0(key, keyBytes, transcoder); if (result == null) { - throw new NoValueException("could not gets the value for Key=" - + key + " for cas"); + throw new NoValueException( + "could not gets the value for Key=" + key + " for cas"); } if (tryCount > operation.getMaxTries()) { throw new TimeoutException("CAS try times is greater than max"); @@ -1779,13 +1788,13 @@ public final boolean cas(String key, final int exp, */ public final boolean cas(String key, final int exp, GetsResponse getsReponse, final CASOperation operation, - final Transcoder transcoder) throws TimeoutException, - InterruptedException, MemcachedException { + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException { key = this.preProcessKey(key); byte[] keyBytes = ByteUtils.getBytes(key); ByteUtils.checkKey(keyBytes); - return this.cas0(key, exp, getsReponse, operation, transcoder, - keyBytes, false); + return this.cas0(key, exp, getsReponse, operation, transcoder, keyBytes, + false); } /* @@ -1808,16 +1817,16 @@ public void casWithNoReply(String key, CASOperation operation) } public void casWithNoReply(String key, GetsResponse getsResponse, - CASOperation operation) throws TimeoutException, - InterruptedException, MemcachedException { + CASOperation operation) + throws TimeoutException, InterruptedException, MemcachedException { this.casWithNoReply(key, 0, getsResponse, operation); } @SuppressWarnings("unchecked") public void casWithNoReply(String key, int exp, - CASOperation operation) throws TimeoutException, - InterruptedException, MemcachedException { + CASOperation operation) + throws TimeoutException, InterruptedException, MemcachedException { key = this.preProcessKey(key); byte[] keyBytes = ByteUtils.getBytes(key); GetsResponse result = this.gets0(key, keyBytes, this.transcoder); @@ -1844,8 +1853,8 @@ public void casWithNoReply(String key, int exp, * net.rubyeye.xmemcached.GetsResponse, net.rubyeye.xmemcached.CASOperation) */ public final boolean cas(final String key, GetsResponse getsReponse, - final CASOperation operation) throws TimeoutException, - InterruptedException, MemcachedException { + final CASOperation operation) + throws TimeoutException, InterruptedException, MemcachedException { return this.cas(key, 0, getsReponse, operation); } @@ -1857,8 +1866,8 @@ public final boolean cas(final String key, GetsResponse getsReponse, */ @SuppressWarnings("unchecked") public final boolean cas(final String key, final int exp, - final CASOperation operation) throws TimeoutException, - InterruptedException, MemcachedException { + final CASOperation operation) + throws TimeoutException, InterruptedException, MemcachedException { return this.cas(key, exp, operation, this.transcoder); } @@ -1869,8 +1878,8 @@ public final boolean cas(final String key, final int exp, * net.rubyeye.xmemcached.CASOperation) */ public final boolean cas(final String key, - final CASOperation operation) throws TimeoutException, - InterruptedException, MemcachedException { + final CASOperation operation) + throws TimeoutException, InterruptedException, MemcachedException { return this.cas(key, 0, operation); } @@ -1884,8 +1893,8 @@ public final boolean delete(final String key, final int time) return this.delete0(key, time, 0, false, this.opTimeout); } - public boolean delete(String key, long opTimeout) throws TimeoutException, - InterruptedException, MemcachedException { + public boolean delete(String key, long opTimeout) + throws TimeoutException, InterruptedException, MemcachedException { return this.delete0(key, 0, 0, false, opTimeout); } @@ -1917,8 +1926,8 @@ public final void deleteWithNoReply(final String key) } private boolean delete0(String key, final int time, long cas, - boolean noreply, long opTimeout) throws MemcachedException, - InterruptedException, TimeoutException { + boolean noreply, long opTimeout) + throws MemcachedException, InterruptedException, TimeoutException { key = this.preProcessKey(key); final byte[] keyBytes = ByteUtils.getBytes(key); ByteUtils.checkKey(keyBytes); @@ -1968,8 +1977,8 @@ public boolean touch(String key, int exp, long opTimeout) return (Boolean) command.getResult(); } - public boolean touch(String key, int exp) throws TimeoutException, - InterruptedException, MemcachedException { + public boolean touch(String key, int exp) + throws TimeoutException, InterruptedException, MemcachedException { return this.touch(key, exp, this.opTimeout); } @@ -1980,8 +1989,8 @@ public T getAndTouch(String key, int newExp, long opTimeout) final byte[] keyBytes = ByteUtils.getBytes(key); ByteUtils.checkKey(keyBytes); CountDownLatch latch = new CountDownLatch(1); - final Command command = this.commandFactory.createGetAndTouchCommand( - key, keyBytes, latch, newExp, false); + final Command command = this.commandFactory + .createGetAndTouchCommand(key, keyBytes, latch, newExp, false); this.latchWait(command, opTimeout, this.sendCommand(command)); command.getIoBuffer().free(); this.checkException(command); @@ -1993,8 +2002,8 @@ public T getAndTouch(String key, int newExp, long opTimeout) } @SuppressWarnings("unchecked") - public T getAndTouch(String key, int newExp) throws TimeoutException, - InterruptedException, MemcachedException { + public T getAndTouch(String key, int newExp) + throws TimeoutException, InterruptedException, MemcachedException { return (T) this.getAndTouch(key, newExp, this.opTimeout); } @@ -2025,8 +2034,8 @@ public long incr(String key, long delta, long initValue, long timeout) } public long incr(String key, long delta, long initValue, long timeout, - int exp) throws TimeoutException, InterruptedException, - MemcachedException { + int exp) + throws TimeoutException, InterruptedException, MemcachedException { key = this.preProcessKey(key); return this.sendIncrOrDecrCommand(key, delta, initValue, CommandType.INCR, false, timeout, exp); @@ -2081,8 +2090,8 @@ public long decr(String key, long delta, long initValue, long timeout) } public long decr(String key, long delta, long initValue, long timeout, - int exp) throws TimeoutException, InterruptedException, - MemcachedException { + int exp) + throws TimeoutException, InterruptedException, MemcachedException { key = this.preProcessKey(key); return this.sendIncrOrDecrCommand(key, delta, initValue, CommandType.DECR, false, timeout, exp); @@ -2093,13 +2102,13 @@ public long decr(String key, long delta, long initValue, long timeout, * * @see net.rubyeye.xmemcached.MemcachedClient#flushAll() */ - public final void flushAll() throws TimeoutException, InterruptedException, - MemcachedException { + public final void flushAll() + throws TimeoutException, InterruptedException, MemcachedException { this.flushAll(this.opTimeout); } - public void flushAllWithNoReply() throws InterruptedException, - MemcachedException { + public void flushAllWithNoReply() + throws InterruptedException, MemcachedException { try { this.flushAllMemcachedServers(this.opTimeout, true, 0); } catch (TimeoutException e) { @@ -2107,8 +2116,8 @@ public void flushAllWithNoReply() throws InterruptedException, } } - public void flushAllWithNoReply(int exptime) throws InterruptedException, - MemcachedException { + public void flushAllWithNoReply(int exptime) + throws InterruptedException, MemcachedException { try { this.flushAllMemcachedServers(this.opTimeout, true, exptime); } catch (TimeoutException e) { @@ -2145,21 +2154,21 @@ public final void flushAll(int exptime, long timeout) * * @see net.rubyeye.xmemcached.MemcachedClient#flushAll(long) */ - public final void flushAll(long timeout) throws TimeoutException, - InterruptedException, MemcachedException { + public final void flushAll(long timeout) + throws TimeoutException, InterruptedException, MemcachedException { this.flushAllMemcachedServers(timeout, false, 0); } private void flushAllMemcachedServers(long timeout, boolean noreply, - int exptime) throws MemcachedException, InterruptedException, - TimeoutException { + int exptime) + throws MemcachedException, InterruptedException, TimeoutException { final Collection sessions = this.connector.getSessionSet(); CountDownLatch latch = new CountDownLatch(sessions.size()); List commands = new ArrayList(sessions.size()); for (Session session : sessions) { if (session != null && !session.isClosed()) { - Command command = this.commandFactory.createFlushAllCommand( - latch, exptime, noreply); + Command command = this.commandFactory + .createFlushAllCommand(latch, exptime, noreply); session.write(command); } else { @@ -2183,8 +2192,8 @@ public void setLoggingLevelVerbosity(InetSocketAddress address, int level) } private void setMemcachedLoggingLevel(InetSocketAddress address, int level, - boolean noreply) throws MemcachedException, InterruptedException, - TimeoutException { + boolean noreply) + throws MemcachedException, InterruptedException, TimeoutException { if (address == null) { throw new IllegalArgumentException("Null adderss"); } @@ -2220,9 +2229,8 @@ public void setLoggingLevelVerbosityWithNoReply(InetSocketAddress address, /* * (non-Javadoc) * - * @see - * net.rubyeye.xmemcached.MemcachedClient#flushAll(java.net.InetSocketAddress - * ) + * @see net.rubyeye.xmemcached.MemcachedClient#flushAll(java.net. + * InetSocketAddress ) */ public final void flushAll(InetSocketAddress address) throws MemcachedException, InterruptedException, TimeoutException { @@ -2232,9 +2240,8 @@ public final void flushAll(InetSocketAddress address) /* * (non-Javadoc) * - * @see - * net.rubyeye.xmemcached.MemcachedClient#flushAll(java.net.InetSocketAddress - * , long) + * @see net.rubyeye.xmemcached.MemcachedClient#flushAll(java.net. + * InetSocketAddress , long) */ public final void flushAll(InetSocketAddress address, long timeout) throws MemcachedException, InterruptedException, TimeoutException { @@ -2242,8 +2249,8 @@ public final void flushAll(InetSocketAddress address, long timeout) } public final void flushAll(InetSocketAddress address, long timeout, - int exptime) throws MemcachedException, InterruptedException, - TimeoutException { + int exptime) + throws MemcachedException, InterruptedException, TimeoutException { this.flushSpecialMemcachedServer(address, timeout, false, exptime); } @@ -2276,8 +2283,8 @@ private void flushSpecialMemcachedServer(InetSocketAddress address, * * @see net.rubyeye.xmemcached.MemcachedClient#flushAll(java.lang.String) */ - public final void flushAll(String host) throws TimeoutException, - InterruptedException, MemcachedException { + public final void flushAll(String host) + throws TimeoutException, InterruptedException, MemcachedException { this.flushAll(AddrUtil.getOneAddress(host), this.opTimeout); } @@ -2301,8 +2308,8 @@ public final Map stats(InetSocketAddress address) */ @SuppressWarnings("unchecked") public final Map stats(InetSocketAddress address, - long timeout) throws MemcachedException, InterruptedException, - TimeoutException { + long timeout) + throws MemcachedException, InterruptedException, TimeoutException { if (address == null) { throw new IllegalArgumentException("Null inetSocketAddress"); } @@ -2315,8 +2322,8 @@ public final Map stats(InetSocketAddress address, + SystemUtils.getRawAddress(address) + ":" + address.getPort() + ",maybe it have not been connected"); } - Command command = this.commandFactory.createStatsCommand(address, - latch, null); + Command command = this.commandFactory.createStatsCommand(address, latch, + null); final Session session = sessionQueue.peek(); session.write(command); this.latchWait(command, timeout, session); @@ -2329,15 +2336,15 @@ public final Map> getStats() } public final Map> getStatsByItem( - String itemName) throws MemcachedException, InterruptedException, - TimeoutException { + String itemName) + throws MemcachedException, InterruptedException, TimeoutException { return this.getStatsByItem(itemName, this.opTimeout); } @SuppressWarnings("unchecked") public final Map> getStatsByItem( - String itemName, long timeout) throws MemcachedException, - InterruptedException, TimeoutException { + String itemName, long timeout) + throws MemcachedException, InterruptedException, TimeoutException { final Set sessionSet = this.connector.getSessionSet(); final Map> collectResult = new HashMap>(); if (sessionSet.size() == 0) { @@ -2407,12 +2414,12 @@ public Map> getStats(long timeout) throws MemcachedException, InterruptedException, TimeoutException { return this.getStatsByItem(null, timeout); } - + /** * For subclass override. */ - protected void shutdown0(){ - + protected void shutdown0() { + } /* @@ -2443,8 +2450,8 @@ public final void shutdown() throws IOException { private long sendIncrOrDecrCommand(final String key, final long delta, long initValue, final CommandType cmdType, boolean noreply, - long operationTimeout, int exp) throws InterruptedException, - TimeoutException, MemcachedException { + long operationTimeout, int exp) + throws InterruptedException, TimeoutException, MemcachedException { final byte[] keyBytes = ByteUtils.getBytes(key); ByteUtils.checkKey(keyBytes); final Command command = this.commandFactory.createIncrDecrCommand(key, @@ -2465,9 +2472,8 @@ private long sendIncrOrDecrCommand(final String key, final long delta, this.transcoder, this.opTimeout)) { return initValue; } else { - return this.sendIncrOrDecrCommand(key, delta, - initValue, cmdType, noreply, operationTimeout, - exp); + return this.sendIncrOrDecrCommand(key, delta, initValue, + cmdType, noreply, operationTimeout, exp); } } else { throw new MemcachedException( @@ -2499,8 +2505,8 @@ public void setConnectionPoolSize(int poolSize) { * * @see net.rubyeye.xmemcached.MemcachedClient#delete(java.lang.String) */ - public final boolean delete(final String key) throws TimeoutException, - InterruptedException, MemcachedException { + public final boolean delete(final String key) + throws TimeoutException, InterruptedException, MemcachedException { return this.delete(key, 0); } @@ -2517,9 +2523,8 @@ public final Transcoder getTranscoder() { /* * (non-Javadoc) * - * @see - * net.rubyeye.xmemcached.MemcachedClient#setTranscoder(net.rubyeye.xmemcached - * .transcoders.Transcoder) + * @see net.rubyeye.xmemcached.MemcachedClient#setTranscoder(net.rubyeye. + * xmemcached .transcoders.Transcoder) */ @SuppressWarnings("unchecked") public final void setTranscoder(final Transcoder transcoder) { @@ -2547,8 +2552,8 @@ private final boolean sendStoreCommand(Command command, long timeout) private static final String CONTINUOUS_TIMEOUT_COUNTER = "ContinuousTimeouts"; protected void latchWait(final Command cmd, final long timeout, - final Session session) throws InterruptedException, - TimeoutException { + final Session session) + throws InterruptedException, TimeoutException { if (cmd.getLatch().await(timeout, TimeUnit.MILLISECONDS)) { AtomicInteger counter = this.getContinuousTimeoutCounter(session); // reset counter. @@ -2569,11 +2574,9 @@ protected void latchWait(final Command cmd, final long timeout, // ignore it. } } - throw new TimeoutException( - "Timed out(" - + timeout - + " milliseconds) waiting for operation while connected to " - + session); + throw new TimeoutException("Timed out(" + timeout + + " milliseconds) waiting for operation while connected to " + + session); } } @@ -2611,7 +2614,8 @@ public Collection getAvailableServers() { return Collections.unmodifiableSet(result); } - public final int getConnectionSizeBySocketAddress(InetSocketAddress address) { + public final int getConnectionSizeBySocketAddress( + InetSocketAddress address) { Queue sessionList = this.connector .getSessionByAddress(address); return sessionList == null ? 0 : sessionList.size(); @@ -2658,8 +2662,8 @@ public void setSanitizeKeys(boolean sanitizeKeys) { this.sanitizeKeys = sanitizeKeys; } - private String decodeKey(String key) throws MemcachedException, - InterruptedException, TimeoutException { + private String decodeKey(String key) + throws MemcachedException, InterruptedException, TimeoutException { try { key = this.sanitizeKeys ? URLDecoder.decode(key, "UTF-8") : key; } catch (UnsupportedEncodingException e) { @@ -2684,8 +2688,8 @@ private String decodeKey(String key) throws MemcachedException, return key; } - private String preProcessKey(String key) throws MemcachedException, - InterruptedException { + private String preProcessKey(String key) + throws MemcachedException, InterruptedException { key = this.keyProvider.process(key); try { key = this.sanitizeKeys ? URLEncoder.encode(key, "UTF-8") : key; @@ -2711,8 +2715,8 @@ public void invalidateNamespace(String ns, long opTimeout) this.incr(key, 1, System.currentTimeMillis(), opTimeout); } - public void invalidateNamespace(String ns) throws MemcachedException, - InterruptedException, TimeoutException { + public void invalidateNamespace(String ns) + throws MemcachedException, InterruptedException, TimeoutException { this.invalidateNamespace(ns, this.opTimeout); } @@ -2725,8 +2729,8 @@ public void invalidateNamespace(String ns) throws MemcachedException, * @throws InterruptedException * @throws MemcachedException */ - public String getNamespace(String ns) throws TimeoutException, - InterruptedException, MemcachedException { + public String getNamespace(String ns) + throws TimeoutException, InterruptedException, MemcachedException { String key = this.keyProvider.process(this.getNSKey(ns)); byte[] keyBytes = ByteUtils.getBytes(key); ByteUtils.checkKey(keyBytes); @@ -2835,8 +2839,9 @@ public boolean isFailureMode() { } public Queue getReconnectRequestQueue() { - return this.connector != null ? this.connector - .getReconnectRequestQueue() : null; + return this.connector != null + ? this.connector.getReconnectRequestQueue() + : null; } } diff --git a/src/main/java/net/rubyeye/xmemcached/XMemcachedClientBuilder.java b/src/main/java/net/rubyeye/xmemcached/XMemcachedClientBuilder.java index 5191ad748..8b106b9e5 100644 --- a/src/main/java/net/rubyeye/xmemcached/XMemcachedClientBuilder.java +++ b/src/main/java/net/rubyeye/xmemcached/XMemcachedClientBuilder.java @@ -78,8 +78,8 @@ public long getOpTimeout() { public void setOpTimeout(long opTimeout) { if (opTimeout <= 0) - throw new IllegalArgumentException("Invalid opTimeout value:" - + opTimeout); + throw new IllegalArgumentException( + "Invalid opTimeout value:" + opTimeout); this.opTimeout = opTimeout; } @@ -132,8 +132,8 @@ public void setSocketOption(SocketOption socketOption, Object value) { } if (!socketOption.type().equals(value.getClass())) { throw new IllegalArgumentException("Expected " - + socketOption.type().getSimpleName() - + " value,but givend " + value.getClass().getSimpleName()); + + socketOption.type().getSimpleName() + " value,but givend " + + value.getClass().getSimpleName()); } this.socketOptions.put(socketOption, value); } @@ -150,7 +150,8 @@ public final void setConnectionPoolSize(int poolSize) { this.connectionPoolSize = poolSize; } - public void removeStateListener(MemcachedClientStateListener stateListener) { + public void removeStateListener( + MemcachedClientStateListener stateListener) { this.stateListeners.remove(stateListener); } @@ -190,12 +191,12 @@ public static final Map getDefaultSocketOptions() { public static final Configuration getDefaultConfiguration() { final Configuration configuration = new Configuration(); - configuration - .setSessionReadBufferSize(MemcachedClient.DEFAULT_SESSION_READ_BUFF_SIZE); + configuration.setSessionReadBufferSize( + MemcachedClient.DEFAULT_SESSION_READ_BUFF_SIZE); configuration .setReadThreadCount(MemcachedClient.DEFAULT_READ_THREAD_COUNT); - configuration - .setSessionIdleTimeout(MemcachedClient.DEFAULT_SESSION_IDLE_TIMEOUT); + configuration.setSessionIdleTimeout( + MemcachedClient.DEFAULT_SESSION_IDLE_TIMEOUT); configuration.setWriteThreadCount(0); return configuration; } @@ -216,7 +217,7 @@ public final void setCommandFactory(CommandFactory commandFactory) { this.commandFactory = commandFactory; } - @SuppressWarnings({ "rawtypes" }) + @SuppressWarnings({"rawtypes"}) protected Transcoder transcoder = new SerializingTranscoder(); public XMemcachedClientBuilder(String addressList) { @@ -247,7 +248,8 @@ public XMemcachedClientBuilder( } public XMemcachedClientBuilder( - Map addressMap, int[] weights) { + Map addressMap, + int[] weights) { this.addressMap = addressMap; this.weights = weights; } @@ -268,9 +270,8 @@ public MemcachedSessionLocator getSessionLocator() { /* * (non-Javadoc) * - * @see - * net.rubyeye.xmemcached.MemcachedClientBuilder#setSessionLocator(net.rubyeye - * .xmemcached.MemcachedSessionLocator) + * @see net.rubyeye.xmemcached.MemcachedClientBuilder#setSessionLocator(net. + * rubyeye .xmemcached.MemcachedSessionLocator) */ public void setSessionLocator(MemcachedSessionLocator sessionLocator) { if (sessionLocator == null) { @@ -332,7 +333,8 @@ public MemcachedClient build() throws IOException { // kestrel protocol use random session locator. if (this.commandFactory.getProtocol() == Protocol.Kestrel) { if (!(this.sessionLocator instanceof RandomMemcachedSessionLocaltor)) { - log.warn("Recommend to use `net.rubyeye.xmemcached.impl.RandomMemcachedSessionLocaltor` as session locator for kestrel protocol."); + log.warn( + "Recommend to use `net.rubyeye.xmemcached.impl.RandomMemcachedSessionLocaltor` as session locator for kestrel protocol."); } } if (this.weights == null) { diff --git a/src/main/java/net/rubyeye/xmemcached/XMemcachedClientMBean.java b/src/main/java/net/rubyeye/xmemcached/XMemcachedClientMBean.java index 55a810378..21b9573cf 100644 --- a/src/main/java/net/rubyeye/xmemcached/XMemcachedClientMBean.java +++ b/src/main/java/net/rubyeye/xmemcached/XMemcachedClientMBean.java @@ -12,11 +12,11 @@ public interface XMemcachedClientMBean { /** - *Add memcached servers + * Add memcached servers * * @param host - * a String in the form of - * "[host1]:[port1],[host2]:[port2] [host3]:[port3],[host4]:[port4]" + * a String in the form of "[host1]:[port1],[host2]:[port2] + * [host3]:[port3],[host4]:[port4]" */ public void addServer(String hostList) throws IOException; @@ -35,7 +35,8 @@ public void addOneServerWithWeight(String server, int weight) * Remove memcached servers * * @param host - * a string in the form of "[host1]:[port1],[host2]:[port2] [host3]:[port3],[host4]:[port4]" + * a string in the form of "[host1]:[port1],[host2]:[port2] + * [host3]:[port3],[host4]:[port4]" */ public void removeServer(String hostList); diff --git a/src/main/java/net/rubyeye/xmemcached/auth/AuthInfo.java b/src/main/java/net/rubyeye/xmemcached/auth/AuthInfo.java index 20ac3ae89..c2e7d7999 100644 --- a/src/main/java/net/rubyeye/xmemcached/auth/AuthInfo.java +++ b/src/main/java/net/rubyeye/xmemcached/auth/AuthInfo.java @@ -11,8 +11,8 @@ public class AuthInfo { private final CallbackHandler callbackHandler; private final String[] mechanisms; - private final int maxAttempts = Integer.parseInt(System.getProperty( - "net.rubyeye.xmemcached.auth_max_attempts", "-1")); + private final int maxAttempts = Integer.parseInt(System + .getProperty("net.rubyeye.xmemcached.auth_max_attempts", "-1")); private int attempts; public synchronized boolean isValid() { @@ -50,7 +50,7 @@ public int getMaxAttempts() { */ public static AuthInfo plain(String username, String password) { return new AuthInfo(new PlainCallbackHandler(username, password), - new String[] { "PLAIN" }); + new String[]{"PLAIN"}); } /** @@ -66,7 +66,7 @@ public static AuthInfo plain(String username, String password) { */ public static AuthInfo cramMD5(String username, String password) { return new AuthInfo(new PlainCallbackHandler(username, password), - new String[] { "CRAM-MD5" }); + new String[]{"CRAM-MD5"}); } /** @@ -82,7 +82,7 @@ public static AuthInfo cramMD5(String username, String password) { */ public static AuthInfo typical(String username, String password) { return new AuthInfo(new PlainCallbackHandler(username, password), - new String[] { "CRAM-MD5", "PLAIN" }); + new String[]{"CRAM-MD5", "PLAIN"}); } public CallbackHandler getCallbackHandler() { diff --git a/src/main/java/net/rubyeye/xmemcached/auth/AuthMemcachedConnectListener.java b/src/main/java/net/rubyeye/xmemcached/auth/AuthMemcachedConnectListener.java index ae2f968fe..7e93061c3 100644 --- a/src/main/java/net/rubyeye/xmemcached/auth/AuthMemcachedConnectListener.java +++ b/src/main/java/net/rubyeye/xmemcached/auth/AuthMemcachedConnectListener.java @@ -15,19 +15,20 @@ * @author dennis * */ -public class AuthMemcachedConnectListener implements - MemcachedSessionConnectListener { +public class AuthMemcachedConnectListener + implements + MemcachedSessionConnectListener { public void onConnect(MemcachedSession session, MemcachedClient client) { MemcachedTCPSession tcpSession = (MemcachedTCPSession) session; Map authInfoMap = client.getAuthInfoMap(); if (authInfoMap != null) { - AuthInfo authInfo = authInfoMap.get(tcpSession - .getRemoteSocketAddress()); + AuthInfo authInfo = authInfoMap + .get(tcpSession.getRemoteSocketAddress()); if (authInfo != null) { XMemcachedClient xMemcachedClient = (XMemcachedClient) client; - AuthTask task = new AuthTask(authInfo, xMemcachedClient - .getCommandFactory(), tcpSession); + AuthTask task = new AuthTask(authInfo, + xMemcachedClient.getCommandFactory(), tcpSession); task.start(); // First time,try to wait if (authInfo.isFirstTime()) { diff --git a/src/main/java/net/rubyeye/xmemcached/auth/AuthTask.java b/src/main/java/net/rubyeye/xmemcached/auth/AuthTask.java index 08da1a357..66af0e417 100644 --- a/src/main/java/net/rubyeye/xmemcached/auth/AuthTask.java +++ b/src/main/java/net/rubyeye/xmemcached/auth/AuthTask.java @@ -61,49 +61,54 @@ private void doAuth() { ResponseStatus responseStatus = ((BaseBinaryCommand) command) .getResponseStatus(); switch (responseStatus) { - case NO_ERROR: - done.set(true); - log.info("Authentication to " - + this.memcachedTCPSession.getRemoteSocketAddress() - + " successfully"); - break; - case AUTH_REQUIRED: - log.error("Authentication failed to " - + this.memcachedTCPSession.getRemoteSocketAddress()); - log.warn("Reopen connection to " - + this.memcachedTCPSession.getRemoteSocketAddress() - + ",beacause auth fail"); - this.memcachedTCPSession.setAuthFailed(true); - - // It it is not first time ,try to sleep 1 second - if (!this.authInfo.isFirstTime()) { - Thread.sleep(1000); - } - this.memcachedTCPSession.close(); - done.set(true); - break; - case FUTHER_AUTH_REQUIRED: - String result = String.valueOf(command.getResult()); - byte[] response = saslClient.evaluateChallenge(ByteUtils - .getBytes(result)); - CountDownLatch latch = new CountDownLatch(1); - command = commandFactory.createAuthStepCommand( - saslClient.getMechanismName(), latch, response); - if (!this.memcachedTCPSession.isClosed()) - this.memcachedTCPSession.write(command); - else { - log.error("Authentication fail,because the connection has been closed"); - throw new RuntimeException( - "Authentication fai,connection has been close"); - } - - break; - default: - log.error("Authentication failed to " - + this.memcachedTCPSession.getRemoteSocketAddress() - + ",response status=" + responseStatus); - command = startAuth(); - break; + case NO_ERROR : + done.set(true); + log.info("Authentication to " + + this.memcachedTCPSession + .getRemoteSocketAddress() + + " successfully"); + break; + case AUTH_REQUIRED : + log.error("Authentication failed to " + + this.memcachedTCPSession + .getRemoteSocketAddress()); + log.warn("Reopen connection to " + + this.memcachedTCPSession + .getRemoteSocketAddress() + + ",beacause auth fail"); + this.memcachedTCPSession.setAuthFailed(true); + + // It it is not first time ,try to sleep 1 second + if (!this.authInfo.isFirstTime()) { + Thread.sleep(1000); + } + this.memcachedTCPSession.close(); + done.set(true); + break; + case FUTHER_AUTH_REQUIRED : + String result = String.valueOf(command.getResult()); + byte[] response = saslClient + .evaluateChallenge(ByteUtils.getBytes(result)); + CountDownLatch latch = new CountDownLatch(1); + command = commandFactory.createAuthStepCommand( + saslClient.getMechanismName(), latch, response); + if (!this.memcachedTCPSession.isClosed()) + this.memcachedTCPSession.write(command); + else { + log.error( + "Authentication fail,because the connection has been closed"); + throw new RuntimeException( + "Authentication fai,connection has been close"); + } + + break; + default : + log.error("Authentication failed to " + + this.memcachedTCPSession + .getRemoteSocketAddress() + + ",response status=" + responseStatus); + command = startAuth(); + break; } @@ -131,17 +136,20 @@ private Command startAuth() throws SaslException { destroySaslClient(); this.saslClient = Sasl.createSaslClient(authInfo.getMechanisms(), null, - "memcached", memcachedTCPSession.getRemoteSocketAddress() - .toString(), null, this.authInfo.getCallbackHandler()); - byte[] response = saslClient.hasInitialResponse() ? saslClient - .evaluateChallenge(EMPTY_BYTES) : EMPTY_BYTES; + "memcached", + memcachedTCPSession.getRemoteSocketAddress().toString(), null, + this.authInfo.getCallbackHandler()); + byte[] response = saslClient.hasInitialResponse() + ? saslClient.evaluateChallenge(EMPTY_BYTES) + : EMPTY_BYTES; CountDownLatch latch = new CountDownLatch(1); Command command = this.commandFactory.createAuthStartCommand( saslClient.getMechanismName(), latch, response); if (!this.memcachedTCPSession.isClosed()) this.memcachedTCPSession.write(command); else { - log.error("Authentication fail,because the connection has been closed"); + log.error( + "Authentication fail,because the connection has been closed"); throw new RuntimeException( "Authentication fai,connection has been close"); } diff --git a/src/main/java/net/rubyeye/xmemcached/auth/PlainCallbackHandler.java b/src/main/java/net/rubyeye/xmemcached/auth/PlainCallbackHandler.java index 10e5266fa..851161abb 100644 --- a/src/main/java/net/rubyeye/xmemcached/auth/PlainCallbackHandler.java +++ b/src/main/java/net/rubyeye/xmemcached/auth/PlainCallbackHandler.java @@ -17,8 +17,6 @@ public class PlainCallbackHandler implements CallbackHandler { private String username; private String password; - - public PlainCallbackHandler(String username, String password) { super(); @@ -26,16 +24,14 @@ public PlainCallbackHandler(String username, String password) { this.password = password; } - - - public void handle(Callback[] callbacks) throws IOException, - UnsupportedCallbackException { + public void handle(Callback[] callbacks) + throws IOException, UnsupportedCallbackException { for (Callback callback : callbacks) { if (callback instanceof NameCallback) { ((NameCallback) callback).setName(this.username); } else if (callback instanceof PasswordCallback) { - ((PasswordCallback) callback).setPassword(password - .toCharArray()); + ((PasswordCallback) callback) + .setPassword(password.toCharArray()); } else throw new UnsupportedCallbackException(callback); } diff --git a/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java b/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java index 913d8ec97..eb01cf2af 100644 --- a/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java +++ b/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java @@ -39,8 +39,9 @@ * @author dennis * */ -public class AWSElasticCacheClient extends XMemcachedClient implements - ConfigUpdateListener { +public class AWSElasticCacheClient extends XMemcachedClient + implements + ConfigUpdateListener { private static final Logger log = LoggerFactory .getLogger(AWSElasticCacheClient.class); @@ -56,8 +57,9 @@ public synchronized void onUpdate(ClusterConfigration config) { removeConfigAddrs(); } - List oldList = this.currentClusterConfiguration != null ? this.currentClusterConfiguration - .getNodeList() : Collections.EMPTY_LIST; + List oldList = this.currentClusterConfiguration != null + ? this.currentClusterConfiguration.getNodeList() + : Collections.EMPTY_LIST; List newList = config.getNodeList(); List addNodes = new ArrayList(); @@ -78,9 +80,9 @@ public synchronized void onUpdate(ClusterConfigration config) { // Begin to update server list for (CacheNode node : addNodes) { try { - this.connect(new InetSocketAddressWrapper(node - .getInetSocketAddress(), this.configPoller - .getCacheNodeOrder(node), 1, null)); + this.connect(new InetSocketAddressWrapper( + node.getInetSocketAddress(), + this.configPoller.getCacheNodeOrder(node), 1, null)); } catch (IOException e) { log.error("Connect to " + node + "failed.", e); } @@ -264,8 +266,8 @@ transcoder, getAddressMapFromConfigAddrs(configAddrs), * * @return */ - public ClusterConfigration getConfig() throws MemcachedException, - InterruptedException, TimeoutException { + public ClusterConfigration getConfig() + throws MemcachedException, InterruptedException, TimeoutException { return this.getConfig("cluster"); } @@ -275,10 +277,10 @@ public ClusterConfigration getConfig() throws MemcachedException, * @since 2.3.0 * @return clusetr config. */ - public ClusterConfigration getConfig(String key) throws MemcachedException, - InterruptedException, TimeoutException { - Command cmd = this.commandFactory.createAWSElasticCacheConfigCommand( - "get", key); + public ClusterConfigration getConfig(String key) + throws MemcachedException, InterruptedException, TimeoutException { + Command cmd = this.commandFactory + .createAWSElasticCacheConfigCommand("get", key); final Session session = this.sendCommand(cmd); this.latchWait(cmd, opTimeout, session); cmd.getIoBuffer().free(); diff --git a/src/main/java/net/rubyeye/xmemcached/aws/AWSUtils.java b/src/main/java/net/rubyeye/xmemcached/aws/AWSUtils.java index a82b26484..c34a81f81 100644 --- a/src/main/java/net/rubyeye/xmemcached/aws/AWSUtils.java +++ b/src/main/java/net/rubyeye/xmemcached/aws/AWSUtils.java @@ -24,8 +24,8 @@ public class AWSUtils { public static ClusterConfigration parseConfiguration(String line) { String[] lines = line.trim().split("(?:\\r?\\n)"); if (lines.length < 2) { - throw new IllegalArgumentException("Incorrect config response:" - + line); + throw new IllegalArgumentException( + "Incorrect config response:" + line); } String configversion = lines[0]; String nodeListStr = lines[1]; @@ -44,12 +44,12 @@ public static ClusterConfigration parseConfiguration(String line) { int firstDelimiter = nodeStr.indexOf(DELIMITER); int secondDelimiter = nodeStr.lastIndexOf(DELIMITER); if (firstDelimiter < 1 || firstDelimiter == secondDelimiter) { - throw new IllegalArgumentException("Invalid server ''" - + nodeStr + "'' in response: " + line); + throw new IllegalArgumentException("Invalid server ''" + nodeStr + + "'' in response: " + line); } String hostName = nodeStr.substring(0, firstDelimiter).trim(); - String ipAddress = nodeStr.substring(firstDelimiter + 1, - secondDelimiter).trim(); + String ipAddress = nodeStr + .substring(firstDelimiter + 1, secondDelimiter).trim(); String portNum = nodeStr.substring(secondDelimiter + 1).trim(); int port = Integer.parseInt(portNum); nodeList.add(new CacheNode(hostName, ipAddress, port)); diff --git a/src/main/java/net/rubyeye/xmemcached/aws/ClusterConfigration.java b/src/main/java/net/rubyeye/xmemcached/aws/ClusterConfigration.java index 27f09eae1..87159edf5 100644 --- a/src/main/java/net/rubyeye/xmemcached/aws/ClusterConfigration.java +++ b/src/main/java/net/rubyeye/xmemcached/aws/ClusterConfigration.java @@ -43,8 +43,8 @@ public ClusterConfigration() { } public String toString() { - StringBuilder nodeList = new StringBuilder("{ Version: " + version - + ", CacheNode List: "); + StringBuilder nodeList = new StringBuilder( + "{ Version: " + version + ", CacheNode List: "); nodeList.append(this.nodeList); nodeList.append("}"); diff --git a/src/main/java/net/rubyeye/xmemcached/aws/ConfigurationPoller.java b/src/main/java/net/rubyeye/xmemcached/aws/ConfigurationPoller.java index 31538b552..2ff068009 100644 --- a/src/main/java/net/rubyeye/xmemcached/aws/ConfigurationPoller.java +++ b/src/main/java/net/rubyeye/xmemcached/aws/ConfigurationPoller.java @@ -95,10 +95,11 @@ public void run() { this.clusterConfigration = newConfig; } else { if (newConfig.getVersion() < currentConfig.getVersion()) { - log.warn("Ignored new config from ElasticCache node, it's too old, current version is: " - + currentConfig.getVersion() - + ", but the new version is: " - + newConfig.getVersion()); + log.warn( + "Ignored new config from ElasticCache node, it's too old, current version is: " + + currentConfig.getVersion() + + ", but the new version is: " + + newConfig.getVersion()); return; } else { this.clusterConfigration = newConfig; diff --git a/src/main/java/net/rubyeye/xmemcached/buffer/CachedBufferAllocator.java b/src/main/java/net/rubyeye/xmemcached/buffer/CachedBufferAllocator.java index 8c9b81cbd..1c42984e4 100644 --- a/src/main/java/net/rubyeye/xmemcached/buffer/CachedBufferAllocator.java +++ b/src/main/java/net/rubyeye/xmemcached/buffer/CachedBufferAllocator.java @@ -73,8 +73,8 @@ public CachedBufferAllocator(int maxPoolSize, int maxCachedBufferSize) { throw new IllegalArgumentException("maxPoolSize: " + maxPoolSize); } if (maxCachedBufferSize < 0) { - throw new IllegalArgumentException("maxCachedBufferSize: " - + maxCachedBufferSize); + throw new IllegalArgumentException( + "maxCachedBufferSize: " + maxCachedBufferSize); } this.maxPoolSize = maxPoolSize; @@ -82,7 +82,6 @@ public CachedBufferAllocator(int maxPoolSize, int maxCachedBufferSize) { this.heapBuffers = new ThreadLocal>>() { - @Override protected Map> initialValue() { return newPoolMap(); @@ -105,14 +104,15 @@ public int getMaxCachedBufferSize() { */ private Map> newPoolMap() { Map> poolMap = new HashMap>(); - int poolSize = this.maxPoolSize == 0 ? DEFAULT_MAX_POOL_SIZE + int poolSize = this.maxPoolSize == 0 + ? DEFAULT_MAX_POOL_SIZE : this.maxPoolSize; for (int i = 0; i < 31; i++) { poolMap.put(1 << i, new CircularQueue(poolSize)); } poolMap.put(0, new CircularQueue(poolSize)); - poolMap.put(Integer.MAX_VALUE, new CircularQueue( - poolSize)); + poolMap.put(Integer.MAX_VALUE, + new CircularQueue(poolSize)); return poolMap; } @@ -169,48 +169,43 @@ public CachedIoBuffer(ByteBuffer origBuffer) { this.origBuffer = origBuffer; } - public void putInt(int i) { this.origBuffer.putInt(i); } - public void putShort(short s) { this.origBuffer.putShort(s); } - public ByteOrder order() { return this.origBuffer.order(); } - public boolean isDirect() { return this.origBuffer.isDirect(); } - public void order(ByteOrder byteOrder) { this.origBuffer.order(byteOrder); } - + public void putLong(long l) { this.origBuffer.putLong(l); } - + public final void free() { - if (this.origBuffer == null - || this.origBuffer.capacity() > CachedBufferAllocator.this.maxCachedBufferSize + if (this.origBuffer == null || this.origBuffer + .capacity() > CachedBufferAllocator.this.maxCachedBufferSize || Thread.currentThread() != this.ownerThread) { return; } // Add to the cache. Queue pool; - pool = CachedBufferAllocator.this.heapBuffers.get().get( - this.origBuffer.capacity()); + pool = CachedBufferAllocator.this.heapBuffers.get() + .get(this.origBuffer.capacity()); if (pool == null) { return; } @@ -223,82 +218,66 @@ public final void free() { } - public final ByteBuffer[] getByteBuffers() { - return new ByteBuffer[] { this.origBuffer }; + return new ByteBuffer[]{this.origBuffer}; } - public final void put(byte[] bytes) { this.origBuffer.put(bytes); } - public final int capacity() { return this.origBuffer.capacity(); } - public final void clear() { this.origBuffer.clear(); } - public final void reset() { this.origBuffer.reset(); } - public final int remaining() { return this.origBuffer.remaining(); } - public final int position() { return this.origBuffer.position(); } - public final void mark() { this.origBuffer.mark(); } - public final int limit() { return this.origBuffer.limit(); } - public final boolean hasRemaining() { return this.origBuffer.hasRemaining(); } - public final void flip() { this.origBuffer.flip(); } - public final void put(byte b) { this.origBuffer.put(b); } - public final void put(ByteBuffer buff) { this.origBuffer.put(buff); } - public final ByteBuffer getByteBuffer() { return this.origBuffer; } - public final void limit(int limit) { this.origBuffer.limit(limit); } - public final void position(int pos) { this.origBuffer.position(pos); } diff --git a/src/main/java/net/rubyeye/xmemcached/buffer/IoBuffer.java b/src/main/java/net/rubyeye/xmemcached/buffer/IoBuffer.java index 85628b6df..1cffee0fc 100644 --- a/src/main/java/net/rubyeye/xmemcached/buffer/IoBuffer.java +++ b/src/main/java/net/rubyeye/xmemcached/buffer/IoBuffer.java @@ -50,11 +50,11 @@ public interface IoBuffer { void put(ByteBuffer buff); void put(byte b); - + void putShort(short s); - + void putInt(int i); - + void putLong(long l); void put(byte[] bytes); diff --git a/src/main/java/net/rubyeye/xmemcached/buffer/SimpleBufferAllocator.java b/src/main/java/net/rubyeye/xmemcached/buffer/SimpleBufferAllocator.java index a9188e659..a082e6d24 100644 --- a/src/main/java/net/rubyeye/xmemcached/buffer/SimpleBufferAllocator.java +++ b/src/main/java/net/rubyeye/xmemcached/buffer/SimpleBufferAllocator.java @@ -22,8 +22,8 @@ @Deprecated public class SimpleBufferAllocator implements BufferAllocator { - public static final IoBuffer EMPTY_IOBUFFER = new SimpleIoBuffer(ByteBuffer - .allocate(0)); + public static final IoBuffer EMPTY_IOBUFFER = new SimpleIoBuffer( + ByteBuffer.allocate(0)); public final IoBuffer allocate(int capacity) { if (capacity == 0) { @@ -40,7 +40,6 @@ public final static BufferAllocator newInstance() { return new SimpleBufferAllocator(); } - public final IoBuffer wrap(ByteBuffer byteBuffer) { return new SimpleIoBuffer(byteBuffer); } diff --git a/src/main/java/net/rubyeye/xmemcached/buffer/SimpleIoBuffer.java b/src/main/java/net/rubyeye/xmemcached/buffer/SimpleIoBuffer.java index 7f4a66eb4..989eeeeab 100644 --- a/src/main/java/net/rubyeye/xmemcached/buffer/SimpleIoBuffer.java +++ b/src/main/java/net/rubyeye/xmemcached/buffer/SimpleIoBuffer.java @@ -24,118 +24,95 @@ public SimpleIoBuffer(ByteBuffer origBuffer) { this.origBuffer = origBuffer; } - public final void free() { this.origBuffer = null; } - public final ByteBuffer[] getByteBuffers() { - return new ByteBuffer[] { this.origBuffer }; + return new ByteBuffer[]{this.origBuffer}; } - public final void put(byte[] bytes) { this.origBuffer.put(bytes); } - public final int capacity() { return this.origBuffer.capacity(); } - public void putInt(int i) { this.origBuffer.putInt(i); } - public void putShort(short s) { this.origBuffer.putShort(s); } - public final void clear() { this.origBuffer.clear(); } - public final void reset() { this.origBuffer.reset(); } - public final int remaining() { return this.origBuffer.remaining(); } - public final int position() { return this.origBuffer.position(); } - public final void mark() { this.origBuffer.mark(); } - public final int limit() { return this.origBuffer.limit(); } - public final boolean hasRemaining() { return this.origBuffer.hasRemaining(); } - public final void flip() { this.origBuffer.flip(); } - public final void put(byte b) { this.origBuffer.put(b); } - public final void put(ByteBuffer buff) { this.origBuffer.put(buff); } - public final ByteBuffer getByteBuffer() { return this.origBuffer; } - public final void limit(int limit) { this.origBuffer.limit(limit); } - public final void position(int pos) { this.origBuffer.position(pos); } - public void order(ByteOrder byteOrder) { this.origBuffer.order(byteOrder); } - public boolean isDirect() { return this.origBuffer.isDirect(); } - public ByteOrder order() { return this.origBuffer.order(); } - public void putLong(long l) { this.origBuffer.putLong(l); diff --git a/src/main/java/net/rubyeye/xmemcached/command/BinaryCommandFactory.java b/src/main/java/net/rubyeye/xmemcached/command/BinaryCommandFactory.java index 7046c2fed..a293ed4f9 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/BinaryCommandFactory.java +++ b/src/main/java/net/rubyeye/xmemcached/command/BinaryCommandFactory.java @@ -64,9 +64,8 @@ public Command createAddCommand(String key, byte[] keyBytes, int exp, public Command createAppendCommand(String key, byte[] keyBytes, Object value, boolean noreply, Transcoder transcoder) { - return new BinaryAppendPrependCommand(key, keyBytes, - CommandType.APPEND, new CountDownLatch(1), 0, 0, value, - noreply, transcoder); + return new BinaryAppendPrependCommand(key, keyBytes, CommandType.APPEND, + new CountDownLatch(1), 0, 0, value, noreply, transcoder); } public Command createCASCommand(String key, byte[] keyBytes, int exp, @@ -88,12 +87,13 @@ public Command createFlushAllCommand(CountDownLatch latch, int delay, public Command createGetCommand(String key, byte[] keyBytes, CommandType cmdType, Transcoder transcoder) { - return new BinaryGetCommand(key, keyBytes, cmdType, new CountDownLatch( - 1), OpCode.GET, false); + return new BinaryGetCommand(key, keyBytes, cmdType, + new CountDownLatch(1), OpCode.GET, false); } public Command createGetMultiCommand(Collection keys, - CountDownLatch latch, CommandType cmdType, Transcoder transcoder) { + CountDownLatch latch, CommandType cmdType, + Transcoder transcoder) { Iterator it = keys.iterator(); String key = null; List bufferList = new ArrayList(); @@ -111,9 +111,8 @@ public Command createGetMultiCommand(Collection keys, } } // last key,create a get command - Command lastCommand = new BinaryGetCommand(key, - ByteUtils.getBytes(key), cmdType, new CountDownLatch(1), - OpCode.GET_KEY, false); + Command lastCommand = new BinaryGetCommand(key, ByteUtils.getBytes(key), + cmdType, new CountDownLatch(1), OpCode.GET_KEY, false); lastCommand.encode(); bufferList.add(lastCommand.getIoBuffer()); totalLength += lastCommand.getIoBuffer().remaining(); @@ -186,8 +185,8 @@ public Command createAuthStartCommand(String mechanism, ByteUtils.getBytes(mechanism), latch, authData); } - public Command createAuthStepCommand(String mechanism, - CountDownLatch latch, byte[] authData) { + public Command createAuthStepCommand(String mechanism, CountDownLatch latch, + byte[] authData) { return new BinaryAuthStepCommand(mechanism, ByteUtils.getBytes(mechanism), latch, authData); } diff --git a/src/main/java/net/rubyeye/xmemcached/command/Command.java b/src/main/java/net/rubyeye/xmemcached/command/Command.java index 71abadf93..ceae5d3f1 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/Command.java +++ b/src/main/java/net/rubyeye/xmemcached/command/Command.java @@ -39,9 +39,9 @@ public abstract class Command implements WriteMessage { public static final byte REQUEST_MAGIC_NUMBER = (byte) (0x80 & 0xFF); public static final byte RESPONSE_MAGIC_NUMBER = (byte) (0x81 & 0xFF); - + private boolean added; - + public boolean isAdded() { return added; } @@ -243,9 +243,9 @@ public abstract boolean decode(MemcachedTCPSession session, ByteBuffer buffer); protected final void decodeError(String msg, Throwable e) { - throw new MemcachedDecodeException( - msg == null ? "decode error,session will be closed,key=" - + this.key : msg, e); + throw new MemcachedDecodeException(msg == null + ? "decode error,session will be closed,key=" + this.key + : msg, e); } protected final void decodeError() { @@ -256,21 +256,22 @@ protected final void decodeError() { protected final boolean decodeError(String line) { if (line.startsWith("ERROR")) { String[] splits = line.split("ERROR"); - String errorMsg = splits.length >= 2 ? splits[1] + String errorMsg = splits.length >= 2 + ? splits[1] : "Unknow command " + getCommandType(); - setException(new UnknownCommandException( - "Response error,error message:" + errorMsg + ",key=" - + this.key)); + setException( + new UnknownCommandException("Response error,error message:" + + errorMsg + ",key=" + this.key)); countDownLatch(); return true; } else if (line.startsWith("CLIENT_ERROR")) { - setException(new MemcachedClientException(getErrorMsg(line, - "Unknown Client Error"))); + setException(new MemcachedClientException( + getErrorMsg(line, "Unknown Client Error"))); this.countDownLatch(); return true; } else if (line.startsWith("SERVER_ERROR")) { - setException(new MemcachedServerException(getErrorMsg(line, - "Unknown Server Error"))); + setException(new MemcachedServerException( + getErrorMsg(line, "Unknown Server Error"))); this.countDownLatch(); return true; } else { diff --git a/src/main/java/net/rubyeye/xmemcached/command/KestrelCommandFactory.java b/src/main/java/net/rubyeye/xmemcached/command/KestrelCommandFactory.java index 20a44c153..7af8ff7fc 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/KestrelCommandFactory.java +++ b/src/main/java/net/rubyeye/xmemcached/command/KestrelCommandFactory.java @@ -70,7 +70,8 @@ public Command createGetCommand(String key, byte[] keyBytes, } public Command createGetMultiCommand(Collection keys, - CountDownLatch latch, CommandType cmdType, Transcoder transcoder) { + CountDownLatch latch, CommandType cmdType, + Transcoder transcoder) { throw new UnsupportedOperationException( "Kestrel doesn't support this operation"); } @@ -138,8 +139,8 @@ public Command createAuthStartCommand(String mechanism, throw new UnsupportedOperationException("Kestrel doesn't support SASL"); } - public Command createAuthStepCommand(String mechanism, - CountDownLatch latch, byte[] authData) { + public Command createAuthStepCommand(String mechanism, CountDownLatch latch, + byte[] authData) { throw new UnsupportedOperationException("Kestrel doesn't support SASL"); } diff --git a/src/main/java/net/rubyeye/xmemcached/command/OperationStatus.java b/src/main/java/net/rubyeye/xmemcached/command/OperationStatus.java index 3306cde1b..6d0bb41a1 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/OperationStatus.java +++ b/src/main/java/net/rubyeye/xmemcached/command/OperationStatus.java @@ -1,9 +1,10 @@ package net.rubyeye.xmemcached.command; /** * Command status. + * * @author dennis * */ public enum OperationStatus { - SENDING,WRITING, SENT, PROCESSING, DONE, CANCEL; + SENDING, WRITING, SENT, PROCESSING, DONE, CANCEL; } diff --git a/src/main/java/net/rubyeye/xmemcached/command/ServerAddressAware.java b/src/main/java/net/rubyeye/xmemcached/command/ServerAddressAware.java index e90f5329b..226ad426c 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/ServerAddressAware.java +++ b/src/main/java/net/rubyeye/xmemcached/command/ServerAddressAware.java @@ -11,8 +11,8 @@ * */ public interface ServerAddressAware { - public static final ByteBuffer VERSION = ByteBuffer.wrap("version\r\n" - .getBytes()); + public static final ByteBuffer VERSION = ByteBuffer + .wrap("version\r\n".getBytes()); public InetSocketAddress getServer(); diff --git a/src/main/java/net/rubyeye/xmemcached/command/TextCommandFactory.java b/src/main/java/net/rubyeye/xmemcached/command/TextCommandFactory.java index 2f4c74030..4edcf6e6e 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/TextCommandFactory.java +++ b/src/main/java/net/rubyeye/xmemcached/command/TextCommandFactory.java @@ -44,14 +44,13 @@ public void setBufferAllocator(BufferAllocator bufferAllocator) { /* * (non-Javadoc) * - * @see - * net.rubyeye.xmemcached.CommandFactory#createDeleteCommand(java.lang.String - * , byte[], int) + * @see net.rubyeye.xmemcached.CommandFactory#createDeleteCommand(java.lang. + * String , byte[], int) */ public final Command createDeleteCommand(final String key, final byte[] keyBytes, final int time, long cas, boolean noreply) { - return new TextDeleteCommand(key, keyBytes, time, - new CountDownLatch(1), noreply); + return new TextDeleteCommand(key, keyBytes, time, new CountDownLatch(1), + noreply); } /* @@ -84,8 +83,8 @@ public final Command createFlushAllCommand(CountDownLatch latch, * @param noreply * @return */ - public final Command createVerbosityCommand(CountDownLatch latch, - int level, boolean noreply) { + public final Command createVerbosityCommand(CountDownLatch latch, int level, + boolean noreply) { return new TextVerbosityCommand(latch, level, noreply); } @@ -161,8 +160,8 @@ public final Command createPrependCommand(final String key, final Command createStoreCommand(String key, byte[] keyBytes, int exp, Object value, CommandType cmdType, boolean noreply, Transcoder transcoder) { - return new TextStoreCommand(key, keyBytes, cmdType, new CountDownLatch( - 1), exp, -1, value, noreply, transcoder); + return new TextStoreCommand(key, keyBytes, cmdType, + new CountDownLatch(1), exp, -1, value, noreply, transcoder); } /* @@ -190,15 +189,16 @@ public final Command createGetCommand(final String key, * net.rubyeye.xmemcached.transcoders.Transcoder) */ public final Command createGetMultiCommand(Collection keys, - CountDownLatch latch, CommandType cmdType, Transcoder transcoder) { + CountDownLatch latch, CommandType cmdType, + Transcoder transcoder) { StringBuilder sb = new StringBuilder(keys.size() * 5); for (String tmpKey : keys) { ByteUtils.checkKey(tmpKey); sb.append(tmpKey).append(" "); } String gatherKey = sb.toString(); - byte[] keyBytes = ByteUtils.getBytes(gatherKey.substring(0, - gatherKey.length() - 1)); + byte[] keyBytes = ByteUtils + .getBytes(gatherKey.substring(0, gatherKey.length() - 1)); return new TextGetMultiCommand(keys.iterator().next(), keyBytes, cmdType, latch, transcoder); } @@ -211,8 +211,8 @@ public final Command createGetMultiCommand(Collection keys, * .String, byte[], int, net.rubyeye.xmemcached.command.CommandType) */ public final Command createIncrDecrCommand(final String key, - final byte[] keyBytes, final long amount, long initial, - int exptime, CommandType cmdType, boolean noreply) { + final byte[] keyBytes, final long amount, long initial, int exptime, + CommandType cmdType, boolean noreply) { return new TextIncrDecrCommand(key, keyBytes, cmdType, new CountDownLatch(1), amount, initial, noreply); } @@ -228,8 +228,8 @@ public Command createAuthStartCommand(String mechanism, "SASL is only supported by binary protocol"); } - public Command createAuthStepCommand(String mechanism, - CountDownLatch latch, byte[] authData) { + public Command createAuthStepCommand(String mechanism, CountDownLatch latch, + byte[] authData) { throw new UnsupportedOperationException( "SASL is only supported by binary protocol"); } diff --git a/src/main/java/net/rubyeye/xmemcached/command/VerbosityCommand.java b/src/main/java/net/rubyeye/xmemcached/command/VerbosityCommand.java index 1828247ca..6ade2390d 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/VerbosityCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/VerbosityCommand.java @@ -23,7 +23,7 @@ public final void setLevel(int logLevel) { public VerbosityCommand(CountDownLatch latch, int level, boolean noreply) { super(CommandType.VERBOSITY, latch); this.level = level; - this.key="[verbosity]"; + this.key = "[verbosity]"; this.noreply = noreply; } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BaseBinaryCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BaseBinaryCommand.java index d8ebcaf2b..c76e1096a 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BaseBinaryCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BaseBinaryCommand.java @@ -45,7 +45,9 @@ * @author dennis * */ -public abstract class BaseBinaryCommand extends Command implements StoreCommand { +public abstract class BaseBinaryCommand extends Command + implements + StoreCommand { static final short DEFAULT_VBUCKET_ID = 0; protected int expTime; protected long cas; @@ -118,64 +120,65 @@ public final void setTranscoder(Transcoder transcoder) { @Override public boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { while (true) { - LABEL: switch (this.decodeStatus) { - case NONE: - if (buffer.remaining() < 24) { - return false; - } else { - this.decodeStatus = BinaryDecodeStatus.READ_HEADER; - } - continue; - case READ_HEADER: - this.readHeader(buffer); - continue; - case READ_EXTRAS: - if (this.readExtras(buffer, this.responseExtrasLength)) { - this.decodeStatus = BinaryDecodeStatus.READ_KEY; + LABEL : switch (this.decodeStatus) { + case NONE : + if (buffer.remaining() < 24) { + return false; + } else { + this.decodeStatus = BinaryDecodeStatus.READ_HEADER; + } continue; - } else { - return false; - } - case READ_KEY: - if (this.readKey(buffer, this.responseKeyLength)) { - this.decodeStatus = BinaryDecodeStatus.READ_VALUE; + case READ_HEADER : + this.readHeader(buffer); continue; - } else { - return false; - } - case READ_VALUE: - if (this.responseStatus == null - || this.responseStatus == ResponseStatus.NO_ERROR) { - if (this.readValue(buffer, this.responseTotalBodyLength, - this.responseKeyLength, this.responseExtrasLength)) { - this.decodeStatus = BinaryDecodeStatus.DONE; + case READ_EXTRAS : + if (this.readExtras(buffer, this.responseExtrasLength)) { + this.decodeStatus = BinaryDecodeStatus.READ_KEY; continue; } else { return false; } - } else { - // Ignore error message - if (ByteUtils.stepBuffer(buffer, - this.responseTotalBodyLength - - this.responseKeyLength - - this.responseExtrasLength)) { - this.decodeStatus = BinaryDecodeStatus.DONE; + case READ_KEY : + if (this.readKey(buffer, this.responseKeyLength)) { + this.decodeStatus = BinaryDecodeStatus.READ_VALUE; continue; } else { return false; } - } - case DONE: - if (this.finish()) { + case READ_VALUE : + if (this.responseStatus == null + || this.responseStatus == ResponseStatus.NO_ERROR) { + if (this.readValue(buffer, this.responseTotalBodyLength, + this.responseKeyLength, + this.responseExtrasLength)) { + this.decodeStatus = BinaryDecodeStatus.DONE; + continue; + } else { + return false; + } + } else { + // Ignore error message + if (ByteUtils.stepBuffer(buffer, + this.responseTotalBodyLength + - this.responseKeyLength + - this.responseExtrasLength)) { + this.decodeStatus = BinaryDecodeStatus.DONE; + continue; + } else { + return false; + } + } + case DONE : + if (this.finish()) { + return true; + } else { + // Do not finish,continue to decode + this.decodeStatus = BinaryDecodeStatus.NONE; + break LABEL; + } + case IGNORE : + buffer.reset(); return true; - } else { - // Do not finish,continue to decode - this.decodeStatus = BinaryDecodeStatus.NONE; - break LABEL; - } - case IGNORE: - buffer.reset(); - return true; } } } @@ -240,8 +243,8 @@ protected boolean readKey(ByteBuffer buffer, int keyLength) { protected boolean readValue(ByteBuffer buffer, int bodyLength, int keyLength, int extrasLength) { - return ByteUtils.stepBuffer(buffer, bodyLength - keyLength - - extrasLength); + return ByteUtils.stepBuffer(buffer, + bodyLength - keyLength - extrasLength); } protected boolean readExtras(ByteBuffer buffer, int extrasLength) { @@ -256,24 +259,24 @@ private int readBodyLength(ByteBuffer buffer) { protected void readStatus(ByteBuffer buffer) { this.responseStatus = ResponseStatus.parseShort(buffer.getShort()); switch (this.responseStatus) { - case NOT_SUPPORTED: - case UNKNOWN_COMMAND: - this.setException(new UnknownCommandException()); - break; - case AUTH_REQUIRED: - case FUTHER_AUTH_REQUIRED: - case VALUE_TOO_BIG: - case INVALID_ARGUMENTS: - case INC_DEC_NON_NUM: - case BELONGS_TO_ANOTHER_SRV: - case AUTH_ERROR: - case OUT_OF_MEMORY: - case INTERNAL_ERROR: - case BUSY: - case TEMP_FAILURE: - this.setException(new MemcachedServerException(this.responseStatus - .errorMessage())); - break; + case NOT_SUPPORTED : + case UNKNOWN_COMMAND : + this.setException(new UnknownCommandException()); + break; + case AUTH_REQUIRED : + case FUTHER_AUTH_REQUIRED : + case VALUE_TOO_BIG : + case INVALID_ARGUMENTS : + case INC_DEC_NON_NUM : + case BELONGS_TO_ANOTHER_SRV : + case AUTH_ERROR : + case OUT_OF_MEMORY : + case INTERNAL_ERROR : + case BUSY : + case TEMP_FAILURE : + this.setException(new MemcachedServerException( + this.responseStatus.errorMessage())); + break; } } @@ -314,8 +317,8 @@ protected boolean readOpCode(ByteBuffer buffer) { if (this.noreply) { return false; } else { - throw new MemcachedDecodeException("Not a proper " - + this.opCode.name() + " response"); + throw new MemcachedDecodeException( + "Not a proper " + this.opCode.name() + " response"); } } return true; diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAWSElasticCacheConfigCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAWSElasticCacheConfigCommand.java index 7b3e03369..9b9e9c61c 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAWSElasticCacheConfigCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAWSElasticCacheConfigCommand.java @@ -39,8 +39,8 @@ public class BinaryAWSElasticCacheConfigCommand extends BaseBinaryCommand { public BinaryAWSElasticCacheConfigCommand(final CountDownLatch latch, String subCommand, String key) { - super(key, ByteUtils.getBytes(key), CommandType.AWS_CONFIG, latch, 0, - 0, latch, false, null); + super(key, ByteUtils.getBytes(key), CommandType.AWS_CONFIG, latch, 0, 0, + latch, false, null); this.commandType = CommandType.AWS_CONFIG; if (subCommand.equals("get")) { this.opCode = OpCode.CONFIG_GET; diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAppendPrependCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAppendPrependCommand.java index 22e708523..9d1758682 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAppendPrependCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAppendPrependCommand.java @@ -44,15 +44,15 @@ public BinaryAppendPrependCommand(String key, byte[] keyBytes, super(key, keyBytes, cmdType, latch, exp, cas, value, noreply, transcoder); switch (cmdType) { - case APPEND: - this.opCode = noreply ? OpCode.APPEND_QUIETLY : OpCode.APPEND; - break; - case PREPEND: - this.opCode = noreply ? OpCode.PREPEND_QUIETLY : OpCode.PREPEND; - break; - default: - throw new UnknownCommandException( - "Not a append or prepend command:" + cmdType.name()); + case APPEND : + this.opCode = noreply ? OpCode.APPEND_QUIETLY : OpCode.APPEND; + break; + case PREPEND : + this.opCode = noreply ? OpCode.PREPEND_QUIETLY : OpCode.PREPEND; + break; + default : + throw new UnknownCommandException( + "Not a append or prepend command:" + cmdType.name()); } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAuthListMechanismsCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAuthListMechanismsCommand.java index fe08cbe72..049bf3659 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAuthListMechanismsCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAuthListMechanismsCommand.java @@ -15,7 +15,8 @@ public class BinaryAuthListMechanismsCommand extends BaseBinaryCommand { public BinaryAuthListMechanismsCommand(CountDownLatch latch) { - super(null, null, CommandType.AUTH_LIST, latch, 0, 0, null, false, null); + super(null, null, CommandType.AUTH_LIST, latch, 0, 0, null, false, + null); this.opCode = OpCode.AUTH_LIST_MECHANISMS; } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAuthStepCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAuthStepCommand.java index 9ea1ebb27..cfc1d38e9 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAuthStepCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAuthStepCommand.java @@ -16,8 +16,8 @@ public class BinaryAuthStepCommand extends BaseBinaryCommand { public BinaryAuthStepCommand(String mechanism, byte[] keyBytes, CountDownLatch latch, byte[] authData) { - super(mechanism, keyBytes, CommandType.AUTH_STEP, latch, 0, 0, - authData, false, null); + super(mechanism, keyBytes, CommandType.AUTH_STEP, latch, 0, 0, authData, + false, null); this.opCode = OpCode.AUTH_STEP; } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryCASCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryCASCommand.java index efe9c8773..0a7f74efb 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryCASCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryCASCommand.java @@ -42,19 +42,18 @@ public BinaryCASCommand(String key, byte[] keyBytes, CommandType cmdType, super(key, keyBytes, cmdType, latch, exp, cas, value, noreply, transcoder); switch (cmdType) { - case CAS: - this.opCode = noreply ? OpCode.SET_QUIETLY : OpCode.SET; - break; - default: - throw new IllegalArgumentException("Unknow cas command type:" - + cmdType); + case CAS : + this.opCode = noreply ? OpCode.SET_QUIETLY : OpCode.SET; + break; + default : + throw new IllegalArgumentException( + "Unknow cas command type:" + cmdType); } - - + } @Override protected long getCasValue() { return this.cas; - } - + } + } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryDecodeStatus.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryDecodeStatus.java index f04b93cdd..1a6cd9ad2 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryDecodeStatus.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryDecodeStatus.java @@ -23,9 +23,10 @@ package net.rubyeye.xmemcached.command.binary; /** * Binary protocol decode status. + * * @author dennis * */ public enum BinaryDecodeStatus { - NONE, READ_HEADER, READ_EXTRAS, READ_KEY, READ_VALUE,DONE,IGNORE + NONE, READ_HEADER, READ_EXTRAS, READ_KEY, READ_VALUE, DONE, IGNORE } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryDeleteCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryDeleteCommand.java index 8e53499a6..c8aa1b7f3 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryDeleteCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryDeleteCommand.java @@ -29,6 +29,7 @@ import net.rubyeye.xmemcached.transcoders.CachedData; /** * Binary delete command + * * @author boyan * */ @@ -37,7 +38,7 @@ public class BinaryDeleteCommand extends BaseBinaryCommand { public BinaryDeleteCommand(String key, byte[] keyBytes, long cas, CommandType cmdType, CountDownLatch latch, boolean noreply) { super(key, keyBytes, cmdType, latch, 0, cas, null, noreply, null); - this.opCode = noreply?OpCode.DELETE_QUIETLY:OpCode.DELETE; + this.opCode = noreply ? OpCode.DELETE_QUIETLY : OpCode.DELETE; } /** @@ -53,7 +54,7 @@ protected void readHeader(ByteBuffer buffer) { } @Override - protected long getCasValue(){ + protected long getCasValue() { if (this.cas > 0) { return this.cas; } else { diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryFlushAllCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryFlushAllCommand.java index 3016f3d43..41d32357a 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryFlushAllCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryFlushAllCommand.java @@ -28,6 +28,7 @@ import net.rubyeye.xmemcached.transcoders.CachedData; /** * Flush command for binary protocol + * * @author dennis * */ @@ -39,7 +40,7 @@ public BinaryFlushAllCommand(CountDownLatch latch, int exptime, boolean noreply) { super("[flush_all]", null, CommandType.FLUSH_ALL, latch, 0, 0, null, noreply, null); - this.opCode=noreply?OpCode.FLUSH_QUIETLY:OpCode.FLUSH; + this.opCode = noreply ? OpCode.FLUSH_QUIETLY : OpCode.FLUSH; this.expTime = exptime; } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryGetAndTouchCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryGetAndTouchCommand.java index 43bf2d4d9..fa9b5a60c 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryGetAndTouchCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryGetAndTouchCommand.java @@ -14,19 +14,20 @@ public class BinaryGetAndTouchCommand extends BinaryGetCommand { public BinaryGetAndTouchCommand(String key, byte[] keyBytes, - CommandType cmdType, CountDownLatch latch, int exp, boolean noreply) { + CommandType cmdType, CountDownLatch latch, int exp, + boolean noreply) { super(key, keyBytes, cmdType, latch, null, noreply); this.expTime = exp; switch (cmdType) { - case GAT: - this.opCode = OpCode.GAT; - break; - case GATQ: - this.opCode = OpCode.GATQ; - break; - default: - throw new IllegalArgumentException("Invalid GAT command type:" - + cmdType); + case GAT : + this.opCode = OpCode.GAT; + break; + case GATQ : + this.opCode = OpCode.GATQ; + break; + default : + throw new IllegalArgumentException( + "Invalid GAT command type:" + cmdType); } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryGetCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryGetCommand.java index 9a2ef03a6..43a8ac3fb 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryGetCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryGetCommand.java @@ -38,8 +38,9 @@ * @author dennis * */ -public class BinaryGetCommand extends BaseBinaryCommand implements - AssocCommandAware { +public class BinaryGetCommand extends BaseBinaryCommand + implements + AssocCommandAware { private String responseKey; private CachedData responseValue; private List assocCommands; @@ -112,7 +113,8 @@ protected boolean readValue(ByteBuffer buffer, int bodyLength, int remainingCapacity = this.responseValue.remainingCapacity(); int remaining = buffer.remaining(); if (remaining < remainingCapacity) { - int length = remaining > remainingCapacity ? remainingCapacity + int length = remaining > remainingCapacity + ? remainingCapacity : remaining; this.responseValue.fillData(buffer, length); return false; @@ -122,8 +124,8 @@ protected boolean readValue(ByteBuffer buffer, int bodyLength, setResult(this.responseValue); return true; } else { - return ByteUtils.stepBuffer(buffer, bodyLength - keyLength - - extrasLength); + return ByteUtils.stepBuffer(buffer, + bodyLength - keyLength - extrasLength); } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryGetMultiCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryGetMultiCommand.java index 11760dce1..41ac4e4b2 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryGetMultiCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryGetMultiCommand.java @@ -42,8 +42,10 @@ * */ @SuppressWarnings("unchecked") -public class BinaryGetMultiCommand extends BaseBinaryCommand implements - MergeCommandsAware, MapReturnValueAware { +public class BinaryGetMultiCommand extends BaseBinaryCommand + implements + MergeCommandsAware, + MapReturnValueAware { private boolean finished; private String responseKey; private long responseCAS; @@ -118,7 +120,8 @@ protected boolean finish() { BinaryGetCommand command = (BinaryGetCommand) nextCommand; command.countDownLatch(); if (command.getAssocCommands() != null) { - for (Command assocCommand : command.getAssocCommands()) { + for (Command assocCommand : command + .getAssocCommands()) { assocCommand.countDownLatch(); } } @@ -144,8 +147,8 @@ protected boolean readKey(ByteBuffer buffer, int keyLength) { CachedData value = new CachedData(); value.setCas(this.responseCAS); value.setFlag(this.responseFlag); - ((Map) this.result) - .put(this.responseKey, value); + ((Map) this.result).put(this.responseKey, + value); } return true; } @@ -164,7 +167,8 @@ protected boolean readValue(ByteBuffer buffer, int bodyLength, int remainingCapacity = responseValue.remainingCapacity(); int remaining = buffer.remaining(); if (remaining < remainingCapacity) { - int length = remaining > remainingCapacity ? remainingCapacity + int length = remaining > remainingCapacity + ? remainingCapacity : remaining; responseValue.fillData(buffer, length); return false; diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryIncrDecrCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryIncrDecrCommand.java index 912a822a5..c6758cd6d 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryIncrDecrCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryIncrDecrCommand.java @@ -29,6 +29,7 @@ import net.rubyeye.xmemcached.transcoders.CachedData; /** * Binary incr/decr command + * * @author dennis * */ @@ -60,15 +61,19 @@ public BinaryIncrDecrCommand(String key, byte[] keyBytes, long amount, this.initial = initial; this.expTime = expTime; switch (cmdType) { - case INCR: - this.opCode = noreply ? OpCode.INCREMENT_QUIETLY : OpCode.INCREMENT; - break; - case DECR: - this.opCode = noreply ? OpCode.DECREMENT_QUIETLY : OpCode.DECREMENT; - break; - default: - throw new IllegalArgumentException("Unknow cmd type for incr/decr:" - + cmdType); + case INCR : + this.opCode = noreply + ? OpCode.INCREMENT_QUIETLY + : OpCode.INCREMENT; + break; + case DECR : + this.opCode = noreply + ? OpCode.DECREMENT_QUIETLY + : OpCode.DECREMENT; + break; + default : + throw new IllegalArgumentException( + "Unknow cmd type for incr/decr:" + cmdType); } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinarySetMultiCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinarySetMultiCommand.java index 557a3e109..d2e7ac898 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinarySetMultiCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinarySetMultiCommand.java @@ -42,8 +42,9 @@ * */ @SuppressWarnings("unchecked") -public class BinarySetMultiCommand extends BaseBinaryCommand implements - MergeCommandsAware { +public class BinarySetMultiCommand extends BaseBinaryCommand + implements + MergeCommandsAware { private boolean finished; private Integer responseOpaque; private Map mergeCommands; diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryStatsCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryStatsCommand.java index aa30260c2..0bca8300d 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryStatsCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryStatsCommand.java @@ -40,8 +40,9 @@ * @author boyan * */ -public class BinaryStatsCommand extends BaseBinaryCommand implements - ServerAddressAware { +public class BinaryStatsCommand extends BaseBinaryCommand + implements + ServerAddressAware { private InetSocketAddress server; private String itemName; @@ -86,8 +87,8 @@ protected boolean finish() { @Override protected void readStatus(ByteBuffer buffer) { - ResponseStatus responseStatus = ResponseStatus.parseShort(buffer - .getShort()); + ResponseStatus responseStatus = ResponseStatus + .parseShort(buffer.getShort()); if (responseStatus == ResponseStatus.UNKNOWN_COMMAND) { setException(new UnknownCommandException()); } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryStoreCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryStoreCommand.java index be41e1fd1..18d483736 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryStoreCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryStoreCommand.java @@ -45,21 +45,21 @@ public BinaryStoreCommand(String key, byte[] keyBytes, CommandType cmdType, super(key, keyBytes, cmdType, latch, exp, cas, value, noreply, transcoder); switch (cmdType) { - case SET: - this.opCode = noreply ? OpCode.SET_QUIETLY : OpCode.SET; - break; - case REPLACE: - this.opCode = noreply ? OpCode.REPLACE_QUIETLY : OpCode.REPLACE; - break; - case ADD: - this.opCode = noreply ? OpCode.ADD_QUIETLY : OpCode.ADD; - break; - case SET_MANY: - //ignore - break; - default: - throw new IllegalArgumentException( - "Unknow cmd type for storage commands:" + cmdType); + case SET : + this.opCode = noreply ? OpCode.SET_QUIETLY : OpCode.SET; + break; + case REPLACE : + this.opCode = noreply ? OpCode.REPLACE_QUIETLY : OpCode.REPLACE; + break; + case ADD : + this.opCode = noreply ? OpCode.ADD_QUIETLY : OpCode.ADD; + break; + case SET_MANY : + // ignore + break; + default : + throw new IllegalArgumentException( + "Unknow cmd type for storage commands:" + cmdType); } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryVersionCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryVersionCommand.java index 1e93ad5e8..33bd82783 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryVersionCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryVersionCommand.java @@ -31,11 +31,13 @@ import net.rubyeye.xmemcached.transcoders.CachedData; /** * Version command for binary protocol + * * @author boyan * */ -public class BinaryVersionCommand extends BaseBinaryCommand implements - ServerAddressAware { +public class BinaryVersionCommand extends BaseBinaryCommand + implements + ServerAddressAware { public InetSocketAddress server; public final InetSocketAddress getServer() { diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/ResponseStatus.java b/src/main/java/net/rubyeye/xmemcached/command/binary/ResponseStatus.java index edbadb6f6..0382bb3cb 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/ResponseStatus.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/ResponseStatus.java @@ -240,45 +240,45 @@ public String errorMessage() { */ public static ResponseStatus parseShort(short value) { switch (value) { - case 0x0000: - return NO_ERROR; - case 0x0001: - return KEY_NOT_FOUND; - case 0x0002: - return KEY_EXISTS; - case 0x0003: - return VALUE_TOO_BIG; - case 0x0004: - return INVALID_ARGUMENTS; - case 0x0005: - return ITEM_NOT_STORED; - case 0x0006: - return INC_DEC_NON_NUM; - case 0x0007: - return BELONGS_TO_ANOTHER_SRV; - case 0x0008: - return AUTH_ERROR; - case 0x0009: - return AUTH_CONTINUE; - case 0x0081: - return UNKNOWN_COMMAND; - case 0x0082: - return OUT_OF_MEMORY; - case 0x0083: - return NOT_SUPPORTED; - case 0x0084: - return INTERNAL_ERROR; - case 0x0085: - return BUSY; - case 0x0086: - return TEMP_FAILURE; - case 0x20: - return AUTH_REQUIRED; - case 0x21: - return FUTHER_AUTH_REQUIRED; - default: - throw new IllegalArgumentException("Unknow Response status:" - + value); + case 0x0000 : + return NO_ERROR; + case 0x0001 : + return KEY_NOT_FOUND; + case 0x0002 : + return KEY_EXISTS; + case 0x0003 : + return VALUE_TOO_BIG; + case 0x0004 : + return INVALID_ARGUMENTS; + case 0x0005 : + return ITEM_NOT_STORED; + case 0x0006 : + return INC_DEC_NON_NUM; + case 0x0007 : + return BELONGS_TO_ANOTHER_SRV; + case 0x0008 : + return AUTH_ERROR; + case 0x0009 : + return AUTH_CONTINUE; + case 0x0081 : + return UNKNOWN_COMMAND; + case 0x0082 : + return OUT_OF_MEMORY; + case 0x0083 : + return NOT_SUPPORTED; + case 0x0084 : + return INTERNAL_ERROR; + case 0x0085 : + return BUSY; + case 0x0086 : + return TEMP_FAILURE; + case 0x20 : + return AUTH_REQUIRED; + case 0x21 : + return FUTHER_AUTH_REQUIRED; + default : + throw new IllegalArgumentException( + "Unknow Response status:" + value); } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/kestrel/KestrelGetCommand.java b/src/main/java/net/rubyeye/xmemcached/command/kestrel/KestrelGetCommand.java index d3b37cdec..3b177e62a 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/kestrel/KestrelGetCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/kestrel/KestrelGetCommand.java @@ -31,6 +31,7 @@ import net.rubyeye.xmemcached.transcoders.TranscoderUtils; /** * Kestrel get command + * * @author dennis * */ diff --git a/src/main/java/net/rubyeye/xmemcached/command/kestrel/KestrelSetCommand.java b/src/main/java/net/rubyeye/xmemcached/command/kestrel/KestrelSetCommand.java index 4f433ce85..401c6eeed 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/kestrel/KestrelSetCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/kestrel/KestrelSetCommand.java @@ -30,6 +30,7 @@ import net.rubyeye.xmemcached.transcoders.Transcoder; /** * kestrel set command + * * @author dennis * */ diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextAWSElasticCacheConfigCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextAWSElasticCacheConfigCommand.java index 4bac2df4f..9447a7aa2 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextAWSElasticCacheConfigCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextAWSElasticCacheConfigCommand.java @@ -60,8 +60,8 @@ public void encode() { // config [sub-command] [key] final byte[] subCmdBytes = ByteUtils.getBytes(this.subCommand); final byte[] keyBytes = ByteUtils.getBytes(this.key); - this.ioBuffer = IoBuffer.allocate(6 + 1 + subCmdBytes.length + 1 - + keyBytes.length + 2); + this.ioBuffer = IoBuffer + .allocate(6 + 1 + subCmdBytes.length + 1 + keyBytes.length + 2); ByteUtils.setArguments(this.ioBuffer, "config", subCmdBytes, keyBytes); this.ioBuffer.flip(); } diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextCASCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextCASCommand.java index ace9e9a74..b7e212174 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextCASCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextCASCommand.java @@ -53,7 +53,8 @@ static enum FailStatus { } @Override - public final boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { + public final boolean decode(MemcachedTCPSession session, + ByteBuffer buffer) { if (buffer == null || !buffer.hasRemaining()) return false; @@ -87,12 +88,12 @@ public final boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { return ByteUtils.stepBuffer(buffer, 8); } else { switch (this.failStatus) { - case NOT_FOUND: - return ByteUtils.stepBuffer(buffer, 11); - case EXISTS: - return ByteUtils.stepBuffer(buffer, 8); - default: - return decodeError(session, buffer); + case NOT_FOUND : + return ByteUtils.stepBuffer(buffer, 11); + case EXISTS : + return ByteUtils.stepBuffer(buffer, 8); + default : + return decodeError(session, buffer); } } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextCacheDumpCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextCacheDumpCommand.java index 08eb71de8..5b5bb84e9 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextCacheDumpCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextCacheDumpCommand.java @@ -34,7 +34,8 @@ public TextCacheDumpCommand(CountDownLatch latch, int itemNumber) { @Override @SuppressWarnings("unchecked") - public final boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { + public final boolean decode(MemcachedTCPSession session, + ByteBuffer buffer) { String line = null; while ((line = ByteUtils.nextLine(buffer)) != null) { if (line.equals("END")) { // at the end @@ -57,7 +58,6 @@ private final boolean done(MemcachedSession session) { @Override public final void encode() { String result = String.format(CACHE_DUMP_COMMAND, this.itemNumber); - this.ioBuffer = IoBuffer - .wrap(ByteBuffer.wrap(result.getBytes())); + this.ioBuffer = IoBuffer.wrap(ByteBuffer.wrap(result.getBytes())); } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextFlushAllCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextFlushAllCommand.java index 604992191..e2d4d7d7b 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextFlushAllCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextFlushAllCommand.java @@ -41,8 +41,8 @@ */ public class TextFlushAllCommand extends Command { - public static final ByteBuffer FLUSH_ALL = ByteBuffer.wrap("flush_all\r\n" - .getBytes()); + public static final ByteBuffer FLUSH_ALL = ByteBuffer + .wrap("flush_all\r\n".getBytes()); protected int exptime; @@ -87,8 +87,8 @@ public final void encode() { ByteUtils.setArguments(this.ioBuffer, "flush_all", Constants.NO_REPLY); } else { - byte[] delayBytes = ByteUtils.getBytes(String - .valueOf(this.exptime)); + byte[] delayBytes = ByteUtils + .getBytes(String.valueOf(this.exptime)); this.ioBuffer = IoBuffer.allocate("flush_all".length() + 2 + delayBytes.length + Constants.NO_REPLY.length + 2); ByteUtils.setArguments(this.ioBuffer, "flush_all", delayBytes, @@ -100,10 +100,10 @@ public final void encode() { this.ioBuffer = IoBuffer.wrap(FLUSH_ALL.slice()); } else { - byte[] delayBytes = ByteUtils.getBytes(String - .valueOf(this.exptime)); - this.ioBuffer = IoBuffer.allocate("flush_all".length() + 1 - + delayBytes.length + 2); + byte[] delayBytes = ByteUtils + .getBytes(String.valueOf(this.exptime)); + this.ioBuffer = IoBuffer.allocate( + "flush_all".length() + 1 + delayBytes.length + 2); ByteUtils.setArguments(this.ioBuffer, "flush_all", delayBytes); } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextGetCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextGetCommand.java index 67116fdbf..5eeba5b59 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextGetCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextGetCommand.java @@ -47,13 +47,16 @@ * @author dennis * */ -public abstract class TextGetCommand extends Command implements - MergeCommandsAware, AssocCommandAware, MapReturnValueAware { +public abstract class TextGetCommand extends Command + implements + MergeCommandsAware, + AssocCommandAware, + MapReturnValueAware { protected Map returnValues; private String currentReturnKey; private int offset; /** - *When MemcachedClient merge get commands,those commans which have the same + * When MemcachedClient merge get commands,those commans which have the same * key will be merged into one get command.The result command's * assocCommands contains all these commands with the same key. */ @@ -100,160 +103,161 @@ public void setParseStatus(ParseStatus parseStatus) { } @Override - public final boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { + public final boolean decode(MemcachedTCPSession session, + ByteBuffer buffer) { while (true) { if (buffer == null || !buffer.hasRemaining()) { return false; } switch (this.parseStatus) { - case NULL: - if (buffer.remaining() < 2) - return false; - int pos = buffer.position(); - byte first = buffer.get(pos); - byte second = buffer.get(pos + 1); - if (first == 'E' && second == 'N') { - this.parseStatus = ParseStatus.END; - // dispatch result - dispatch(); - this.currentReturnKey = null; - continue; - } else if (first == 'V') { - this.parseStatus = ParseStatus.VALUE; - this.wasFirst = false; - continue; - } else { - return decodeError(session, buffer); - } - case END: - // END\r\n - return ByteUtils.stepBuffer(buffer, 5); - case VALUE: - // VALUE[SPACE] - if (ByteUtils.stepBuffer(buffer, 6)) { - this.parseStatus = ParseStatus.KEY; - continue; - } else { - return false; - } - case KEY: - String item = getItem(buffer, ' '); - if (item == null) { - return false; - } else { - this.currentReturnKey = item; - this.returnValues.put(this.currentReturnKey, - new CachedData()); - this.parseStatus = ParseStatus.FLAG; - continue; - } - case FLAG: - item = getItem(buffer, ' '); - if (item == null) { - return false; - } else { - final CachedData cachedData = this.returnValues - .get(this.currentReturnKey); - cachedData.setFlag(Integer.parseInt(item)); - this.parseStatus = ParseStatus.DATA_LEN; - continue; - } - case DATA_LEN: - item = getItem(buffer, '\r', ' '); - if (item == null) { - return false; - } else { - final CachedData cachedData = this.returnValues - .get(this.currentReturnKey); - cachedData.setCapacity(Integer.parseInt(item)); - assert (cachedData.getCapacity() >= 0); - cachedData.setData(new byte[cachedData.getCapacity()]); - this.parseStatus = ParseStatus.DATA_LEN_DONE; - continue; - } - case DATA_LEN_DONE: - if (buffer.remaining() < 1) { - return false; - } else { - pos = buffer.position(); - first = buffer.get(pos); - // check if buffer has cas value - if (first == '\n') { - // skip '\n' - buffer.position(pos + 1); - this.parseStatus = ParseStatus.DATA; + case NULL : + if (buffer.remaining() < 2) + return false; + int pos = buffer.position(); + byte first = buffer.get(pos); + byte second = buffer.get(pos + 1); + if (first == 'E' && second == 'N') { + this.parseStatus = ParseStatus.END; + // dispatch result + dispatch(); + this.currentReturnKey = null; + continue; + } else if (first == 'V') { + this.parseStatus = ParseStatus.VALUE; + this.wasFirst = false; continue; } else { - this.parseStatus = ParseStatus.CAS; + return decodeError(session, buffer); + } + case END : + // END\r\n + return ByteUtils.stepBuffer(buffer, 5); + case VALUE : + // VALUE[SPACE] + if (ByteUtils.stepBuffer(buffer, 6)) { + this.parseStatus = ParseStatus.KEY; continue; + } else { + return false; } - } - case CAS: - // has cas value - item = getItem(buffer, '\r'); - if (item == null) { - return false; - } else { - final CachedData cachedData = this.returnValues + case KEY : + String item = getItem(buffer, ' '); + if (item == null) { + return false; + } else { + this.currentReturnKey = item; + this.returnValues.put(this.currentReturnKey, + new CachedData()); + this.parseStatus = ParseStatus.FLAG; + continue; + } + case FLAG : + item = getItem(buffer, ' '); + if (item == null) { + return false; + } else { + final CachedData cachedData = this.returnValues + .get(this.currentReturnKey); + cachedData.setFlag(Integer.parseInt(item)); + this.parseStatus = ParseStatus.DATA_LEN; + continue; + } + case DATA_LEN : + item = getItem(buffer, '\r', ' '); + if (item == null) { + return false; + } else { + final CachedData cachedData = this.returnValues + .get(this.currentReturnKey); + cachedData.setCapacity(Integer.parseInt(item)); + assert (cachedData.getCapacity() >= 0); + cachedData.setData(new byte[cachedData.getCapacity()]); + this.parseStatus = ParseStatus.DATA_LEN_DONE; + continue; + } + case DATA_LEN_DONE : + if (buffer.remaining() < 1) { + return false; + } else { + pos = buffer.position(); + first = buffer.get(pos); + // check if buffer has cas value + if (first == '\n') { + // skip '\n' + buffer.position(pos + 1); + this.parseStatus = ParseStatus.DATA; + continue; + } else { + this.parseStatus = ParseStatus.CAS; + continue; + } + } + case CAS : + // has cas value + item = getItem(buffer, '\r'); + if (item == null) { + return false; + } else { + final CachedData cachedData = this.returnValues + .get(this.currentReturnKey); + cachedData.setCas(Long.parseLong(item)); + this.parseStatus = ParseStatus.CAS_DONE; + continue; + } + case CAS_DONE : + if (buffer.remaining() < 1) { + return false; + } else { + this.parseStatus = ParseStatus.DATA; + // skip '\n' + buffer.position(buffer.position() + 1); + continue; + } + case DATA : + final CachedData value = this.returnValues .get(this.currentReturnKey); - cachedData.setCas(Long.parseLong(item)); - this.parseStatus = ParseStatus.CAS_DONE; - continue; - } - case CAS_DONE: - if (buffer.remaining() < 1) { - return false; - } else { - this.parseStatus = ParseStatus.DATA; - // skip '\n' - buffer.position(buffer.position() + 1); - continue; - } - case DATA: - final CachedData value = this.returnValues - .get(this.currentReturnKey); - int remaining = buffer.remaining(); - int remainingCapacity = value.remainingCapacity(); - assert (remainingCapacity >= 0); - // Data is not enough,return false - if (remaining < remainingCapacity + 2) { - int length = remaining > remainingCapacity ? remainingCapacity - : remaining; - value.fillData(buffer, length); - return false; - } else if (remainingCapacity > 0) { - value.fillData(buffer, remainingCapacity); - } - assert (value.remainingCapacity() == 0); - buffer - .position(buffer.position() - + ByteUtils.SPLIT.remaining()); + int remaining = buffer.remaining(); + int remainingCapacity = value.remainingCapacity(); + assert (remainingCapacity >= 0); + // Data is not enough,return false + if (remaining < remainingCapacity + 2) { + int length = remaining > remainingCapacity + ? remainingCapacity + : remaining; + value.fillData(buffer, length); + return false; + } else if (remainingCapacity > 0) { + value.fillData(buffer, remainingCapacity); + } + assert (value.remainingCapacity() == 0); + buffer.position( + buffer.position() + ByteUtils.SPLIT.remaining()); - Map mergetCommands = getMergeCommands(); - if (mergetCommands != null) { - final TextGetCommand command = (TextGetCommand) mergetCommands - .remove(this.currentReturnKey); - if (command != null) { - command.setResult(value); - command.countDownLatch(); - this.mergeCount--; - if (command.getAssocCommands() != null) { - for (Command assocCommand : command - .getAssocCommands()) { - assocCommand.setResult(value); - assocCommand.countDownLatch(); - this.mergeCount--; + Map mergetCommands = getMergeCommands(); + if (mergetCommands != null) { + final TextGetCommand command = (TextGetCommand) mergetCommands + .remove(this.currentReturnKey); + if (command != null) { + command.setResult(value); + command.countDownLatch(); + this.mergeCount--; + if (command.getAssocCommands() != null) { + for (Command assocCommand : command + .getAssocCommands()) { + assocCommand.setResult(value); + assocCommand.countDownLatch(); + this.mergeCount--; + } } - } + } } - } - this.currentReturnKey = null; - this.parseStatus = ParseStatus.NULL; - continue; - default: - return decodeError(session, buffer); + this.currentReturnKey = null; + this.parseStatus = ParseStatus.NULL; + continue; + default : + return decodeError(session, buffer); } } @@ -314,8 +318,9 @@ public final void setReturnValues(Map returnValues) { @Override public void encode() { byte[] cmdBytes = this.commandType == CommandType.GET_ONE - || this.commandType == CommandType.GET_MANY ? Constants.GET - : Constants.GETS; + || this.commandType == CommandType.GET_MANY + ? Constants.GET + : Constants.GETS; this.ioBuffer = IoBuffer.allocate(cmdBytes.length + Constants.CRLF.length + 1 + this.keyBytes.length); ByteUtils.setArguments(this.ioBuffer, cmdBytes, this.keyBytes); diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextGetMultiCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextGetMultiCommand.java index f88ff4703..2ac6bda20 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextGetMultiCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextGetMultiCommand.java @@ -28,6 +28,7 @@ import net.rubyeye.xmemcached.transcoders.Transcoder; /** * Bulk-get command for text protocol + * * @author dennis * */ @@ -35,7 +36,7 @@ public class TextGetMultiCommand extends TextGetCommand { @SuppressWarnings("unchecked") public TextGetMultiCommand(String key, byte[] keyBytes, CommandType cmdType, - CountDownLatch latch,Transcoder transcoder) { + CountDownLatch latch, Transcoder transcoder) { super(key, keyBytes, cmdType, latch); this.transcoder = transcoder; } diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextIncrDecrCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextIncrDecrCommand.java index 0f5e94d37..0624ea607 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextIncrDecrCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextIncrDecrCommand.java @@ -44,9 +44,8 @@ public class TextIncrDecrCommand extends Command { private long delta; private final long initial; - public TextIncrDecrCommand(String key, byte[] keyBytes, - CommandType cmdType, CountDownLatch latch, long delta, - long initial, boolean noreply) { + public TextIncrDecrCommand(String key, byte[] keyBytes, CommandType cmdType, + CountDownLatch latch, long delta, long initial, boolean noreply) { super(key, keyBytes, cmdType, latch); this.delta = delta; this.noreply = noreply; @@ -62,7 +61,8 @@ public final void setDelta(int delta) { } @Override - public final boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { + public final boolean decode(MemcachedTCPSession session, + ByteBuffer buffer) { String line = ByteUtils.nextLine(buffer); if (line != null) { if (line.equals("NOT_FOUND")) { @@ -87,7 +87,8 @@ public final boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { @Override public final void encode() { - byte[] cmdBytes = this.commandType == CommandType.INCR ? Constants.INCR + byte[] cmdBytes = this.commandType == CommandType.INCR + ? Constants.INCR : Constants.DECR; int size = 6 + this.keyBytes.length + ByteUtils.stringSize(this.getDelta()) + Constants.CRLF.length; diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextQuitCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextQuitCommand.java index 92fdf7a0c..9ed87f946 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextQuitCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextQuitCommand.java @@ -45,7 +45,8 @@ public TextQuitCommand() { static final IoBuffer QUIT = IoBuffer.wrap("quit\r\n".getBytes()); @Override - public final boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { + public final boolean decode(MemcachedTCPSession session, + ByteBuffer buffer) { // do nothing return true; } diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextStatsCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextStatsCommand.java index 7c4e97298..de4fcad2a 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextStatsCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextStatsCommand.java @@ -44,8 +44,8 @@ * */ public class TextStatsCommand extends Command implements ServerAddressAware { - public static final ByteBuffer STATS = ByteBuffer.wrap("stats\r\n" - .getBytes()); + public static final ByteBuffer STATS = ByteBuffer + .wrap("stats\r\n".getBytes()); private InetSocketAddress server; private String itemName; @@ -77,12 +77,14 @@ public TextStatsCommand(InetSocketAddress server, CountDownLatch latch, @Override @SuppressWarnings("unchecked") - public final boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { + public final boolean decode(MemcachedTCPSession session, + ByteBuffer buffer) { String line = null; while ((line = ByteUtils.nextLine(buffer)) != null) { if (line.equals("END")) { // at the end return done(session); - } else if (line.startsWith("STAT") || line.startsWith("PREFIX") || line.startsWith("ITEM") ) { + } else if (line.startsWith("STAT") || line.startsWith("PREFIX") + || line.startsWith("ITEM")) { // Fixed issue 126 String[] items = line.split(" "); ((Map) getResult()).put(items[1], items[2]); diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextStoreCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextStoreCommand.java index a96716c85..0f42c0d4f 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextStoreCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextStoreCommand.java @@ -42,7 +42,7 @@ * @author dennis * */ -public class TextStoreCommand extends Command implements StoreCommand{ +public class TextStoreCommand extends Command implements StoreCommand { protected int expTime; protected long cas; protected Object value; @@ -131,21 +131,21 @@ public boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { private String getCommandName() { switch (this.commandType) { - case ADD: - return "add"; - case SET: - return "set"; - case REPLACE: - return "replace"; - case APPEND: - return "append"; - case PREPEND: - return "prepend"; - case CAS: - return "cas"; - default: - throw new IllegalArgumentException(this.commandType.name() - + " is not a store command"); + case ADD : + return "add"; + case SET : + return "set"; + case REPLACE : + return "replace"; + case APPEND : + return "append"; + case PREPEND : + return "prepend"; + case CAS : + return "cas"; + default : + throw new IllegalArgumentException( + this.commandType.name() + " is not a store command"); } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextTouchCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextTouchCommand.java index 1db931ad4..895d63c16 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextTouchCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextTouchCommand.java @@ -62,7 +62,8 @@ public void setExpTime(int expTime) { } @Override - public final boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { + public final boolean decode(MemcachedTCPSession session, + ByteBuffer buffer) { if (buffer == null || !buffer.hasRemaining()) { return false; } @@ -96,8 +97,8 @@ public final boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { @Override public final void encode() { byte[] cmdBytes = Constants.TOUCH; - int size = 7 + this.keyBytes.length - + ByteUtils.stringSize(this.expTime) + Constants.CRLF.length; + int size = 7 + this.keyBytes.length + ByteUtils.stringSize(this.expTime) + + Constants.CRLF.length; if (isNoreply()) { size += 8; } diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextVerbosityCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextVerbosityCommand.java index 7d47ce22b..e4cf27fa0 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextVerbosityCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextVerbosityCommand.java @@ -42,7 +42,8 @@ public class TextVerbosityCommand extends VerbosityCommand { public static final String VERBOSITY = "verbosity"; - public TextVerbosityCommand(CountDownLatch latch, int level, boolean noreply) { + public TextVerbosityCommand(CountDownLatch latch, int level, + boolean noreply) { super(latch, level, noreply); } @@ -77,8 +78,8 @@ public void encode() { ByteUtils.setArguments(this.ioBuffer, VERBOSITY, levelBytes, Constants.NO_REPLY); } else { - this.ioBuffer = IoBuffer.allocate(2 + 1 + VERBOSITY.length() - + levelBytes.length); + this.ioBuffer = IoBuffer + .allocate(2 + 1 + VERBOSITY.length() + levelBytes.length); ByteUtils.setArguments(this.ioBuffer, VERBOSITY, levelBytes); } diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextVersionCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextVersionCommand.java index 93fc7d457..ccf4f4509 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextVersionCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextVersionCommand.java @@ -59,7 +59,8 @@ public TextVersionCommand(final CountDownLatch latch, } @Override - public final boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { + public final boolean decode(MemcachedTCPSession session, + ByteBuffer buffer) { String line = ByteUtils.nextLine(buffer); if (line != null) { if (line.startsWith("VERSION")) { diff --git a/src/main/java/net/rubyeye/xmemcached/exception/MemcachedClientException.java b/src/main/java/net/rubyeye/xmemcached/exception/MemcachedClientException.java index a3a9e4a50..0fcccc846 100644 --- a/src/main/java/net/rubyeye/xmemcached/exception/MemcachedClientException.java +++ b/src/main/java/net/rubyeye/xmemcached/exception/MemcachedClientException.java @@ -12,6 +12,7 @@ package net.rubyeye.xmemcached.exception; /** * Memcached Client Exception + * * @author dennis * */ diff --git a/src/main/java/net/rubyeye/xmemcached/exception/MemcachedDecodeException.java b/src/main/java/net/rubyeye/xmemcached/exception/MemcachedDecodeException.java index c44db309a..021c78327 100644 --- a/src/main/java/net/rubyeye/xmemcached/exception/MemcachedDecodeException.java +++ b/src/main/java/net/rubyeye/xmemcached/exception/MemcachedDecodeException.java @@ -2,6 +2,7 @@ /** * Memcached decode exception + * * @author dennis * */ diff --git a/src/main/java/net/rubyeye/xmemcached/exception/MemcachedServerException.java b/src/main/java/net/rubyeye/xmemcached/exception/MemcachedServerException.java index 0808c085e..dae901484 100644 --- a/src/main/java/net/rubyeye/xmemcached/exception/MemcachedServerException.java +++ b/src/main/java/net/rubyeye/xmemcached/exception/MemcachedServerException.java @@ -12,6 +12,7 @@ package net.rubyeye.xmemcached.exception; /** * Memcached server exception + * * @author dennis * */ diff --git a/src/main/java/net/rubyeye/xmemcached/exception/NoValueException.java b/src/main/java/net/rubyeye/xmemcached/exception/NoValueException.java index 753143993..ead18d788 100644 --- a/src/main/java/net/rubyeye/xmemcached/exception/NoValueException.java +++ b/src/main/java/net/rubyeye/xmemcached/exception/NoValueException.java @@ -13,6 +13,7 @@ /** * Memcached Client Exception + * * @author bmahe * */ diff --git a/src/main/java/net/rubyeye/xmemcached/impl/AbstractMemcachedSessionLocator.java b/src/main/java/net/rubyeye/xmemcached/impl/AbstractMemcachedSessionLocator.java index 92920d598..6ace894bd 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/AbstractMemcachedSessionLocator.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/AbstractMemcachedSessionLocator.java @@ -8,8 +8,9 @@ * @author dennis * @date 2010-12-25 */ -public abstract class AbstractMemcachedSessionLocator implements - MemcachedSessionLocator { +public abstract class AbstractMemcachedSessionLocator + implements + MemcachedSessionLocator { protected boolean failureMode; diff --git a/src/main/java/net/rubyeye/xmemcached/impl/ArrayMemcachedSessionLocator.java b/src/main/java/net/rubyeye/xmemcached/impl/ArrayMemcachedSessionLocator.java index 6bf10b4b8..1d91d025d 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/ArrayMemcachedSessionLocator.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/ArrayMemcachedSessionLocator.java @@ -28,8 +28,9 @@ * @author dennis * */ -public class ArrayMemcachedSessionLocator extends - AbstractMemcachedSessionLocator { +public class ArrayMemcachedSessionLocator + extends + AbstractMemcachedSessionLocator { private HashAlgorithm hashAlgorighm; private transient volatile List> sessions; @@ -108,10 +109,10 @@ public final void updateSessions(final Collection list) { subList = new ArrayList(); subList.add(target); } else { - if (session.getRemoteSocketAddress().equals( - target.getRemoteSocketAddress())) { + if (session.getRemoteSocketAddress() + .equals(target.getRemoteSocketAddress())) { subList.add(session); - } else { + } else { tmpList.add(subList); target = session; subList = new ArrayList(); diff --git a/src/main/java/net/rubyeye/xmemcached/impl/ClosedMemcachedTCPSession.java b/src/main/java/net/rubyeye/xmemcached/impl/ClosedMemcachedTCPSession.java index 326451dd4..0b7aca89a 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/ClosedMemcachedTCPSession.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/ClosedMemcachedTCPSession.java @@ -47,7 +47,6 @@ public void setAllowReconnect(boolean allow) { this.allowReconnect = allow; } - public void clearAttributes() { } diff --git a/src/main/java/net/rubyeye/xmemcached/impl/ConnectFuture.java b/src/main/java/net/rubyeye/xmemcached/impl/ConnectFuture.java index 90b36c783..65762e3a1 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/ConnectFuture.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/ConnectFuture.java @@ -45,5 +45,4 @@ public InetSocketAddressWrapper getInetSocketAddressWrapper() { return this.inetSocketAddressWrapper; } - } diff --git a/src/main/java/net/rubyeye/xmemcached/impl/ElectionMemcachedSessionLocator.java b/src/main/java/net/rubyeye/xmemcached/impl/ElectionMemcachedSessionLocator.java index f8155c160..969f5c931 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/ElectionMemcachedSessionLocator.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/ElectionMemcachedSessionLocator.java @@ -37,8 +37,9 @@ * @author dennis * */ -public class ElectionMemcachedSessionLocator extends - AbstractMemcachedSessionLocator { +public class ElectionMemcachedSessionLocator + extends + AbstractMemcachedSessionLocator { private transient volatile List sessions; @@ -74,18 +75,17 @@ private Session getSessionByElection(String key, if (session instanceof MemcachedTCPSession) { MemcachedSession tcpSession = (MemcachedSession) session; for (int i = 0; i < tcpSession.getWeight(); i++) { - hash = this.hashAlgorithm.hash(session - .getRemoteSocketAddress().toString() - + "-" + i + key); + hash = this.hashAlgorithm + .hash(session.getRemoteSocketAddress().toString() + + "-" + i + key); if (hash > highScore) { highScore = hash; result = session; } } } else { - hash = this.hashAlgorithm.hash(session.getRemoteSocketAddress() - .toString() - + key); + hash = this.hashAlgorithm.hash( + session.getRemoteSocketAddress().toString() + key); } if (hash > highScore) { diff --git a/src/main/java/net/rubyeye/xmemcached/impl/FlowControlLinkedTransferQueue.java b/src/main/java/net/rubyeye/xmemcached/impl/FlowControlLinkedTransferQueue.java index cbc9ad2ee..69548a17c 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/FlowControlLinkedTransferQueue.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/FlowControlLinkedTransferQueue.java @@ -10,8 +10,9 @@ import com.google.code.yanf4j.core.WriteMessage; import com.google.code.yanf4j.util.LinkedTransferQueue; -public class FlowControlLinkedTransferQueue extends - LinkedTransferQueue { +public class FlowControlLinkedTransferQueue + extends + LinkedTransferQueue { private FlowControl flowControl; public FlowControlLinkedTransferQueue(FlowControl flowControl) { diff --git a/src/main/java/net/rubyeye/xmemcached/impl/KetamaMemcachedSessionLocator.java b/src/main/java/net/rubyeye/xmemcached/impl/KetamaMemcachedSessionLocator.java index 023e911cb..47509ffbf 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/KetamaMemcachedSessionLocator.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/KetamaMemcachedSessionLocator.java @@ -46,8 +46,9 @@ * @author dennis * */ -public class KetamaMemcachedSessionLocator extends -AbstractMemcachedSessionLocator { +public class KetamaMemcachedSessionLocator + extends + AbstractMemcachedSessionLocator { static final int NUM_REPS = 160; private transient volatile TreeMap> ketamaSessions = new TreeMap>(); @@ -94,8 +95,9 @@ public KetamaMemcachedSessionLocator(HashAlgorithm alg, this.cwNginxUpstreamConsistent = cwNginxUpstreamConsistent; this.gwhalinMemcachedJavaClientCompatibiltyConsistent = gwhalinMemcachedJavaClientCompatibiltyConsistent; } - - public KetamaMemcachedSessionLocator(List list, HashAlgorithm alg) { + + public KetamaMemcachedSessionLocator(List list, + HashAlgorithm alg) { super(); this.hashAlg = alg; this.cwNginxUpstreamConsistent = false; @@ -125,10 +127,11 @@ private final void buildMap(Collection list, HashAlgorithm alg) { } else { sockStr = ((MemcachedSession) session) .getInetSocketAddressWrapper() - .getInetSocketAddress().getHostName() + ":" + - ((MemcachedSession) session) - .getInetSocketAddressWrapper() - .getInetSocketAddress().getPort(); + .getInetSocketAddress().getHostName() + + ":" + + ((MemcachedSession) session) + .getInetSocketAddressWrapper() + .getInetSocketAddress().getPort(); } } if (sockStr == null) { diff --git a/src/main/java/net/rubyeye/xmemcached/impl/KeyIteratorImpl.java b/src/main/java/net/rubyeye/xmemcached/impl/KeyIteratorImpl.java index d6a0736ba..81e894280 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/KeyIteratorImpl.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/KeyIteratorImpl.java @@ -55,13 +55,13 @@ public void close() { public boolean hasNext() { return (this.itemNumbersList != null && !this.itemNumbersList.isEmpty()) - || (this.currentKeyList != null && !this.currentKeyList - .isEmpty()); + || (this.currentKeyList != null + && !this.currentKeyList.isEmpty()); } @SuppressWarnings("unchecked") - public String next() throws MemcachedException, TimeoutException, - InterruptedException { + public String next() + throws MemcachedException, TimeoutException, InterruptedException { if (!hasNext()) { throw new NoSuchElementException(); } @@ -88,20 +88,21 @@ public String next() throws MemcachedException, TimeoutException, throw new TimeoutException("stats cachedump timeout"); } if (textCacheDumpCommand.getException() != null) { - if (textCacheDumpCommand.getException() instanceof MemcachedException) { + if (textCacheDumpCommand + .getException() instanceof MemcachedException) { throw (MemcachedException) textCacheDumpCommand .getException(); } else { - throw new MemcachedServerException(textCacheDumpCommand - .getException()); + throw new MemcachedServerException( + textCacheDumpCommand.getException()); } } this.currentKeyList = (LinkedList) textCacheDumpCommand .getResult(); } else { - throw new MemcachedException( - this.memcachedClient.getProtocol().name() - + " protocol doesn't support iterating all keys in memcached"); + throw new MemcachedException(this.memcachedClient.getProtocol() + .name() + + " protocol doesn't support iterating all keys in memcached"); } return next(); } diff --git a/src/main/java/net/rubyeye/xmemcached/impl/LibmemcachedMemcachedSessionLocator.java b/src/main/java/net/rubyeye/xmemcached/impl/LibmemcachedMemcachedSessionLocator.java index a6e038bb0..c77c9c155 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/LibmemcachedMemcachedSessionLocator.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/LibmemcachedMemcachedSessionLocator.java @@ -30,8 +30,9 @@ * @author dennis * */ -public class LibmemcachedMemcachedSessionLocator extends - AbstractMemcachedSessionLocator { +public class LibmemcachedMemcachedSessionLocator + extends + AbstractMemcachedSessionLocator { static final int DEFAULT_NUM_REPS = 100; private transient volatile TreeMap> ketamaSessions = new TreeMap>(); @@ -111,7 +112,7 @@ public final Session getSessionByHash(final long hash) { resultHash = tailMap.firstKey(); } } - // + // // if (!sessionMap.containsKey(resultHash)) { // resultHash = sessionMap.ceilingKey(resultHash); // if (resultHash == null && sessionMap.size() > 0) { diff --git a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedClientStateListenerAdapter.java b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedClientStateListenerAdapter.java index f00354f0a..bc7bb264b 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedClientStateListenerAdapter.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedClientStateListenerAdapter.java @@ -34,8 +34,9 @@ * @author dennis * */ -public class MemcachedClientStateListenerAdapter implements - ControllerStateListener { +public class MemcachedClientStateListenerAdapter + implements + ControllerStateListener { private final MemcachedClientStateListener memcachedClientStateListener; private final MemcachedClient memcachedClient; @@ -55,29 +56,24 @@ public final MemcachedClient getMemcachedClient() { return this.memcachedClient; } - public final void onAllSessionClosed(Controller acceptor) { } - public final void onException(Controller acceptor, Throwable t) { this.memcachedClientStateListener.onException(this.memcachedClient, t); } - public final void onReady(Controller acceptor) { } - public final void onStarted(Controller acceptor) { this.memcachedClientStateListener.onStarted(this.memcachedClient); } - public final void onStopped(Controller acceptor) { this.memcachedClientStateListener.onShutDown(this.memcachedClient); diff --git a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java index 33b85ab02..63cd2fa27 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java @@ -64,8 +64,9 @@ * * @author dennis */ -public class MemcachedConnector extends SocketChannelController implements - Connector { +public class MemcachedConnector extends SocketChannelController + implements + Connector { private final DelayQueue waitingQueue = new DelayQueue(); private BufferAllocator bufferAllocator; @@ -80,9 +81,9 @@ public class MemcachedConnector extends SocketChannelController implements private boolean failureMode; private final ConcurrentHashMap/* - * standby - * sessions - */> standbySessionMap = new ConcurrentHashMap>(); + * standby + * sessions + */> standbySessionMap = new ConcurrentHashMap>(); private final FlowControl flowControl; @@ -149,7 +150,8 @@ public void run() { } } } else { - log.info("Remove invalid reconnect task for " + address); + log.info( + "Remove invalid reconnect task for " + address); // remove reconnect task } } catch (InterruptedException e) { @@ -168,8 +170,9 @@ private void rescheduleConnectRequest(ReconnectRequest request) { InetSocketAddress address = request.getInetSocketAddressWrapper() .getInetSocketAddress(); // update timestamp for next reconnecting - request.updateNextReconnectTimeStamp(MemcachedConnector.this.healSessionInterval - * request.getTries()); + request.updateNextReconnectTimeStamp( + MemcachedConnector.this.healSessionInterval + * request.getTries()); log.error("Reconnected to " + address + " fail"); // add to tail MemcachedConnector.this.waitingQueue.offer(request); @@ -231,8 +234,8 @@ public synchronized void addSession(Session session) { // Remember the first time address resolved and use it in all // application lifecycle. if (addrWrapper.getRemoteAddressStr() == null) { - addrWrapper.setRemoteAddressStr(String.valueOf(session - .getRemoteSocketAddress())); + addrWrapper.setRemoteAddressStr( + String.valueOf(session.getRemoteSocketAddress())); } InetSocketAddress mainNodeAddress = addrWrapper.getMainNodeAddress(); @@ -256,8 +259,8 @@ private void addMainSession(Session session) { Queue sessions = this.sessionMap.get(remoteSocketAddress); if (sessions == null) { sessions = new ConcurrentLinkedQueue(); - Queue oldSessions = this.sessionMap.putIfAbsent( - remoteSocketAddress, sessions); + Queue oldSessions = this.sessionMap + .putIfAbsent(remoteSocketAddress, sessions); if (null != oldSessions) { sessions = oldSessions; } @@ -295,8 +298,8 @@ private void addStandbySession(Session session, List sessions = this.standbySessionMap.get(mainNodeAddress); if (sessions == null) { sessions = new CopyOnWriteArrayList(); - List oldSessions = this.standbySessionMap.putIfAbsent( - mainNodeAddress, sessions); + List oldSessions = this.standbySessionMap + .putIfAbsent(mainNodeAddress, sessions); if (null != oldSessions) { sessions = oldSessions; } @@ -322,9 +325,8 @@ public void removeReconnectRequest(InetSocketAddress inetSocketAddress) { if (request.getInetSocketAddressWrapper().getInetSocketAddress() .equals(inetSocketAddress)) { it.remove(); - log.warn("Remove invalid reconnect task for " - + request.getInetSocketAddressWrapper() - .getInetSocketAddress()); + log.warn("Remove invalid reconnect task for " + request + .getInetSocketAddressWrapper().getInetSocketAddress()); } } } @@ -368,8 +370,8 @@ private void removeMainSession(Session session) { log.info("Remove a session: " + SystemUtils.getRawAddress(remoteSocketAddress) + ":" + remoteSocketAddress.getPort()); - Queue sessionQueue = this.sessionMap.get(session - .getRemoteSocketAddress()); + Queue sessionQueue = this.sessionMap + .get(session.getRemoteSocketAddress()); if (null != sessionQueue) { sessionQueue.remove(session); if (sessionQueue.size() == 0) { @@ -407,30 +409,28 @@ public void onConnect(SelectionKey key) throws IOException { if (!((SocketChannel) key.channel()).finishConnect()) { this.cancelKey(key); future.failure(new IOException("Connect to " - + SystemUtils.getRawAddress(future - .getInetSocketAddressWrapper() - .getInetSocketAddress()) - + ":" - + future.getInetSocketAddressWrapper() - .getInetSocketAddress().getPort() + " fail")); + + SystemUtils.getRawAddress( + future.getInetSocketAddressWrapper() + .getInetSocketAddress()) + + ":" + future.getInetSocketAddressWrapper() + .getInetSocketAddress().getPort() + + " fail")); } else { key.attach(null); - this.addSession(this.createSession( - (SocketChannel) key.channel(), - future.getInetSocketAddressWrapper())); + this.addSession( + this.createSession((SocketChannel) key.channel(), + future.getInetSocketAddressWrapper())); future.setResult(Boolean.TRUE); } } catch (Exception e) { future.failure(e); this.cancelKey(key); - throw new IOException("Connect to " - + SystemUtils.getRawAddress(future - .getInetSocketAddressWrapper() - .getInetSocketAddress()) + throw new IOException("Connect to " + SystemUtils.getRawAddress( + future.getInetSocketAddressWrapper().getInetSocketAddress()) + ":" + future.getInetSocketAddressWrapper() - .getInetSocketAddress().getPort() + " fail," - + e.getMessage()); + .getInetSocketAddress().getPort() + + " fail," + e.getMessage()); } } @@ -475,8 +475,8 @@ public Future connect(InetSocketAddressWrapper addressWrapper) this.selectorManager.registerChannel(socketChannel, SelectionKey.OP_CONNECT, future); } else { - this.addSession(this.createSession(socketChannel, - addressWrapper)); + this.addSession( + this.createSession(socketChannel, addressWrapper)); future.setResult(true); } return future; @@ -495,8 +495,8 @@ public void closeChannel(Selector selector) throws IOException { private final Random random = new Random(); public Session send(final Command msg) throws MemcachedException { - MemcachedSession session = (MemcachedSession) this.findSessionByKey(msg - .getKey()); + MemcachedSession session = (MemcachedSession) this + .findSessionByKey(msg.getKey()); if (session == null) { throw new MemcachedException( "There is no available connection at this moment"); @@ -507,9 +507,9 @@ public Session send(final Command msg) throws MemcachedException { } if (session.isClosed()) { throw new MemcachedException("Session(" - + SystemUtils.getRawAddress(session - .getRemoteSocketAddress()) + ":" - + session.getRemoteSocketAddress().getPort() + + SystemUtils + .getRawAddress(session.getRemoteSocketAddress()) + + ":" + session.getRemoteSocketAddress().getPort() + ") has been closed"); } if (session.isAuthFailed()) { @@ -523,11 +523,11 @@ public Session send(final Command msg) throws MemcachedException { private MemcachedSession findStandbySession(MemcachedSession session) { if (this.failureMode) { List sessionList = this - .getStandbySessionListByMainNodeAddr(session - .getRemoteSocketAddress()); + .getStandbySessionListByMainNodeAddr( + session.getRemoteSocketAddress()); if (sessionList != null && !sessionList.isEmpty()) { - return (MemcachedTCPSession) sessionList.get(this.random - .nextInt(sessionList.size())); + return (MemcachedTCPSession) sessionList + .get(this.random.nextInt(sessionList.size())); } } return session; @@ -629,8 +629,8 @@ public FlowControl getNoReplyOpsFlowControl() { @Override protected NioSession buildSession(SocketChannel sc) { Queue queue = this.buildQueue(); - final NioSessionConfig sessionCofig = this - .buildSessionConfig(sc, queue); + final NioSessionConfig sessionCofig = this.buildSessionConfig(sc, + queue); MemcachedTCPSession session = new MemcachedTCPSession(sessionCofig, this.configuration.getSessionReadBufferSize(), this.optimiezer, this.getReadThreadCount(), this.commandFactory); diff --git a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java index 406e6c1d2..feb18bd33 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java @@ -57,8 +57,8 @@ */ public class MemcachedHandler extends HandlerAdapter { - private static final int MAX_HEARTBEAT_THREADS = Integer.parseInt(System - .getProperty("xmemcached.heartbeat.max_threads", + private static final int MAX_HEARTBEAT_THREADS = Integer + .parseInt(System.getProperty("xmemcached.heartbeat.max_threads", String.valueOf(SystemUtils.getSystemThreadCount()))); private final StatisticsHandler statisticsHandler; @@ -75,7 +75,8 @@ public class MemcachedHandler extends HandlerAdapter { * On receive message from memcached server */ @Override - public final void onMessageReceived(final Session session, final Object msg) { + public final void onMessageReceived(final Session session, + final Object msg) { Command command = (Command) msg; if (this.statisticsHandler.isStatistics()) { if (command.getCopiedMergeCount() > 0 @@ -121,16 +122,16 @@ public final void onMessageSent(Session session, Object msg) { // After message sent,we can set the buffer to be null for gc friendly. command.setIoBuffer(EMPTY_BUF); switch (command.getCommandType()) { - case ADD: - case APPEND: - case SET: - case SET_MANY: - // After message sent,we can set the value to be null for gc - // friendly. - if (command instanceof StoreCommand) { - ((StoreCommand) command).setValue(null); - } - break; + case ADD : + case APPEND : + case SET : + case SET_MANY : + // After message sent,we can set the value to be null for gc + // friendly. + if (command instanceof StoreCommand) { + ((StoreCommand) command).setValue(null); + } + break; } } @@ -186,12 +187,11 @@ public void onSessionIdle(Session session) { private void checkHeartBeat(Session session) { if (this.enableHeartBeat) { - log.debug( - "Check session ({}) is alive,send heartbeat", - session.getRemoteSocketAddress() == null ? "unknown" - : SystemUtils.getRawAddress(session - .getRemoteSocketAddress()) - + ":" + log.debug("Check session ({}) is alive,send heartbeat", + session.getRemoteSocketAddress() == null + ? "unknown" + : SystemUtils.getRawAddress( + session.getRemoteSocketAddress()) + ":" + session.getRemoteSocketAddress() .getPort()); Command versionCommand = null; @@ -207,16 +207,15 @@ private void checkHeartBeat(Session session) { session.write(versionCommand); // Start a check thread,avoid blocking reactor thread if (this.heartBeatThreadPool != null) { - this.heartBeatThreadPool.execute(new CheckHeartResultThread( - versionCommand, session)); + this.heartBeatThreadPool.execute( + new CheckHeartResultThread(versionCommand, session)); } } } private static final String HEART_BEAT_FAIL_COUNT_ATTR = "heartBeatFailCount"; - private static final int MAX_HEART_BEAT_FAIL_COUNT = Integer - .parseInt(System.getProperty("xmemcached.heartbeat.max.fail.times", - "3")); + private static final int MAX_HEART_BEAT_FAIL_COUNT = Integer.parseInt( + System.getProperty("xmemcached.heartbeat.max.fail.times", "3")); final static class CheckHeartResultThread implements Runnable { @@ -247,12 +246,12 @@ public void run() { } if (heartBeatFailCount.get() > MAX_HEART_BEAT_FAIL_COUNT) { log.warn("Session(" - + SystemUtils.getRawAddress(this.session - .getRemoteSocketAddress()) + + SystemUtils.getRawAddress( + this.session.getRemoteSocketAddress()) + ":" + this.session.getRemoteSocketAddress() - .getPort() + ") heartbeat fail " - + heartBeatFailCount.get() + .getPort() + + ") heartbeat fail " + heartBeatFailCount.get() + " times,close session and try to heal it"); this.session.close();// close session heartBeatFailCount.set(0); @@ -291,22 +290,23 @@ public void stop() { this.heartBeatThreadPool.shutdown(); } - final long HEARTBEAT_PERIOD = Long.parseLong(System.getProperty( - "xmemcached.heartbeat.period", "5000")); + final long HEARTBEAT_PERIOD = Long.parseLong( + System.getProperty("xmemcached.heartbeat.period", "5000")); public void start() { final String name = "XMemcached-HeartBeatPool[" + client.getName() + "]"; final AtomicInteger threadCounter = new AtomicInteger(); - long keepAliveTime = client.getConnector().getSessionIdleTimeout() * 3 / 2; + long keepAliveTime = client.getConnector().getSessionIdleTimeout() * 3 + / 2; this.heartBeatThreadPool = new ThreadPoolExecutor(1, MAX_HEARTBEAT_THREADS, keepAliveTime, TimeUnit.MILLISECONDS, new SynchronousQueue(), new ThreadFactory() { public Thread newThread(Runnable r) { - Thread t = new Thread(r, name + "-" - + threadCounter.getAndIncrement()); + Thread t = new Thread(r, + name + "-" + threadCounter.getAndIncrement()); t.setDaemon(true); if (t.getPriority() != Thread.NORM_PRIORITY) { t.setPriority(Thread.NORM_PRIORITY); diff --git a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedSessionComparator.java b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedSessionComparator.java index 3d29824b6..1f3556a7d 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedSessionComparator.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedSessionComparator.java @@ -13,8 +13,10 @@ * @author dennis * */ -public class MemcachedSessionComparator implements Comparator, - Serializable { +public class MemcachedSessionComparator + implements + Comparator, + Serializable { static final long serialVersionUID = -1L; public int compare(Session o1, Session o2) { diff --git a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedTCPSession.java b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedTCPSession.java index dbb65cab3..7a44a34e8 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedTCPSession.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedTCPSession.java @@ -42,15 +42,17 @@ * * @author dennis */ -public class MemcachedTCPSession extends NioTCPSession implements - MemcachedSession { +public class MemcachedTCPSession extends NioTCPSession + implements + MemcachedSession { /** * Command which are already sent */ protected BlockingQueue commandAlreadySent; - private final AtomicReference currentCommand = new LinkedTransferQueue.PaddedAtomicReference(null); + private final AtomicReference currentCommand = new LinkedTransferQueue.PaddedAtomicReference( + null); private SocketAddress remoteSocketAddress; // prevent channel is closed private int sendBufferSize; @@ -79,7 +81,8 @@ public MemcachedTCPSession(NioSessionConfig sessionConfig, this.sendBufferSize = 8 * 1024; } } - this.commandAlreadySent = (BlockingQueue)SystemUtils.createTransferQueue(); + this.commandAlreadySent = (BlockingQueue) SystemUtils + .createTransferQueue(); this.commandFactory = commandFactory; } @@ -107,18 +110,18 @@ public String toString() { } public void destroy() { - Command command = this.currentCommand.get(); + Command command = this.currentCommand.get(); if (command != null) { - command.setException(new MemcachedException( - "Session has been closed")); + command.setException( + new MemcachedException("Session has been closed")); CountDownLatch latch = command.getLatch(); if (latch != null) { latch.countDown(); } } while ((command = this.commandAlreadySent.poll()) != null) { - command.setException(new MemcachedException( - "Session has been closed")); + command.setException( + new MemcachedException("Session has been closed")); CountDownLatch latch = command.getLatch(); if (latch != null) { latch.countDown(); @@ -151,11 +154,10 @@ protected WriteMessage preprocessWriteMessage(WriteMessage writeMessage) { this.writeQueue, this.commandAlreadySent, this.sendBufferSize); } - + currentCommand.setStatus(OperationStatus.WRITING); - if (!currentCommand.isAdded() - && (!currentCommand.isNoreply() || this.commandFactory - .getProtocol() == Protocol.Binary)) { + if (!currentCommand.isAdded() && (!currentCommand.isNoreply() + || this.commandFactory.getProtocol() == Protocol.Binary)) { currentCommand.setAdded(true); this.addCommand(currentCommand); } diff --git a/src/main/java/net/rubyeye/xmemcached/impl/Optimizer.java b/src/main/java/net/rubyeye/xmemcached/impl/Optimizer.java index 5c78f355f..0bafb988d 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/Optimizer.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/Optimizer.java @@ -74,8 +74,7 @@ public class Optimizer implements OptimizerMBean, MemcachedOptimizer { private Protocol protocol = Protocol.Binary; public Optimizer(Protocol protocol) { - XMemcachedMbeanServer.getInstance().registMBean( - this, + XMemcachedMbeanServer.getInstance().registMBean(this, this.getClass().getPackage().getName() + ":type=" + this.getClass().getSimpleName() + "-" + MemcachedClientNameHolder.getName()); @@ -104,7 +103,8 @@ public boolean isOptimizeGet() { } public void setOptimizeGet(boolean optimiezeGet) { - log.warn(optimiezeGet ? "Enable merge get commands" + log.warn(optimiezeGet + ? "Enable merge get commands" : "Disable merge get commands"); this.optimiezeGet = optimiezeGet; } @@ -114,7 +114,8 @@ public boolean isOptimizeMergeBuffer() { } public void setOptimizeMergeBuffer(boolean optimiezeMergeBuffer) { - log.warn(optimiezeMergeBuffer ? "Enable merge buffers" + log.warn(optimiezeMergeBuffer + ? "Enable merge buffers" : "Disable merge buffers"); this.optimiezeMergeBuffer = optimiezeMergeBuffer; } @@ -128,8 +129,8 @@ public Command optimize(final Command currentCommand, optimiezeCommand); optimiezeCommand = this.optimiezeSet(writeQueue, executingCmds, optimiezeCommand, sendBufferSize); - optimiezeCommand = this.optimiezeMergeBuffer(optimiezeCommand, writeQueue, - executingCmds, sendBufferSize); + optimiezeCommand = this.optimiezeMergeBuffer(optimiezeCommand, + writeQueue, executingCmds, sendBufferSize); return optimiezeCommand; } @@ -147,8 +148,8 @@ public final Command optimiezeMergeBuffer(Command optimiezeCommand, if (log.isDebugEnabled()) { log.debug("Optimieze merge buffer:" + optimiezeCommand.toString()); } - if (this.optimiezeMergeBuffer - && optimiezeCommand.getIoBuffer().remaining() < sendBufferSize - 24) { + if (this.optimiezeMergeBuffer && optimiezeCommand.getIoBuffer() + .remaining() < sendBufferSize - 24) { optimiezeCommand = this.mergeBuffer(optimiezeCommand, writeQueue, executingCmds, sendBufferSize); } @@ -182,10 +183,11 @@ public final Command optimiezeSet(final Queue writeQueue, int sendBufferSize) { if (this.optimiezeSet && optimiezeCommand.getCommandType() == CommandType.SET - && !optimiezeCommand.isNoreply() && this.protocol == Protocol.Binary) { - optimiezeCommand = this.mergeSetCommands(optimiezeCommand, writeQueue, - executingCmds, optimiezeCommand.getCommandType(), - sendBufferSize); + && !optimiezeCommand.isNoreply() + && this.protocol == Protocol.Binary) { + optimiezeCommand = this.mergeSetCommands(optimiezeCommand, + writeQueue, executingCmds, + optimiezeCommand.getCommandType(), sendBufferSize); } return optimiezeCommand; } @@ -222,10 +224,11 @@ private final Command mergeBuffer(final Command firstCommand, wasFirst = false; } // if it is get_one command,try to merge get commands - if ((nextCmd.getCommandType() == CommandType.GET_ONE || nextCmd - .getCommandType() == CommandType.GETS_ONE) && this.optimiezeGet) { - nextCmd = this.mergeGetCommands(nextCmd, writeQueue, executingCmds, - nextCmd.getCommandType()); + if ((nextCmd.getCommandType() == CommandType.GET_ONE + || nextCmd.getCommandType() == CommandType.GETS_ONE) + && this.optimiezeGet) { + nextCmd = this.mergeGetCommands(nextCmd, writeQueue, + executingCmds, nextCmd.getCommandType()); } commands.add(nextCmd); @@ -243,8 +246,8 @@ private final Command mergeBuffer(final Command firstCommand, byte[] ba = command.getIoBuffer().array(); System.arraycopy(ba, 0, buf, offset, ba.length); offset += ba.length; - if (command != lastCommand - && (!command.isNoreply() || command instanceof BaseBinaryCommand)) { + if (command != lastCommand && (!command.isNoreply() + || command instanceof BaseBinaryCommand)) { executingCmds.add(command); } } @@ -273,12 +276,12 @@ static interface CommandCollector { public void visit(Command command); public void finish(); - + public CommandCollector reset(); } static class KeyStringCollector implements CommandCollector { - char[] buf = new char[1024*2]; + char[] buf = new char[1024 * 2]; int count = 0; boolean wasFirst = true; @@ -310,7 +313,8 @@ private void expandCapacity(int minimumCapacity) { newCapacity = minimumCapacity; } char[] copy = new char[newCapacity]; - System.arraycopy(this.buf, 0, copy, 0, Math.min(this.buf.length, newCapacity)); + System.arraycopy(this.buf, 0, copy, 0, + Math.min(this.buf.length, newCapacity)); this.buf = copy; } @@ -340,8 +344,6 @@ private static class BinarySetQCollector implements CommandCollector { BinaryStoreCommand prevCommand; Map mergeCommands; - - public CommandCollector reset() { this.bufferList.clear(); this.totalBytes = 0; @@ -372,8 +374,9 @@ public void visit(Command command) { if (this.prevCommand != null) { // first n-1 send setq command BinaryStoreCommand setqCmd = new BinaryStoreCommand( - this.prevCommand.getKey(), this.prevCommand.getKeyBytes(), - CommandType.SET, null, this.prevCommand.getExpTime(), + this.prevCommand.getKey(), + this.prevCommand.getKeyBytes(), CommandType.SET, null, + this.prevCommand.getExpTime(), this.prevCommand.getCas(), // set noreply to be true this.prevCommand.getValue(), true, @@ -384,7 +387,6 @@ public void visit(Command command) { setqCmd.encode(); this.totalBytes += setqCmd.getIoBuffer().remaining(); - this.bufferList.add(setqCmd.getIoBuffer()); // GC friendly setqCmd.setIoBuffer(MemcachedHandler.EMPTY_BUF); @@ -411,7 +413,8 @@ public void finish() { CommandType.SET, null, this.prevCommand.getExpTime(), this.prevCommand.getCas(), // set noreply to be false. - this.prevCommand.getValue(), false, this.prevCommand.getTranscoder()); + this.prevCommand.getValue(), false, + this.prevCommand.getTranscoder()); // We must set the opaque to get error message. int opaque = OpaqueGenerater.getInstance().getNextValue(); setqCmd.setOpaque(opaque); @@ -429,8 +432,8 @@ private static class BinaryGetQCollector implements CommandCollector { ArrayList bufferList = new ArrayList(50); int totalBytes; Command prevCommand; - - public CommandCollector reset(){ + + public CommandCollector reset() { this.bufferList.clear(); this.totalBytes = 0; this.prevCommand = null; @@ -456,8 +459,9 @@ public void visit(Command command) { if (this.prevCommand != null) { // first n-1 send getq command Command getqCommand = new BinaryGetCommand( - this.prevCommand.getKey(), this.prevCommand.getKeyBytes(), null, - null, OpCode.GET_KEY_QUIETLY, true); + this.prevCommand.getKey(), + this.prevCommand.getKeyBytes(), null, null, + OpCode.GET_KEY_QUIETLY, true); getqCommand.encode(); this.totalBytes += getqCommand.getIoBuffer().remaining(); this.bufferList.add(getqCommand.getIoBuffer()); @@ -485,7 +489,8 @@ private final Command mergeGetCommands(final Command currentCmd, CommandType expectedCommandType) { Map mergeCommands = null; int mergeCount = 1; - final CommandCollector commandCollector = this.createGetCommandCollector(); + final CommandCollector commandCollector = this + .createGetCommandCollector(); currentCmd.setStatus(OperationStatus.WRITING); commandCollector.visit(currentCmd); @@ -515,7 +520,7 @@ private final Command mergeGetCommands(final Command currentCmd, .get(removedCommand.getKey()); if (mergedGetCommand.getAssocCommands() == null) { mergedGetCommand - .setAssocCommands(new ArrayList(5)); + .setAssocCommands(new ArrayList(5)); } mergedGetCommand.getAssocCommands().add(removedCommand); } else { @@ -539,21 +544,22 @@ private final Command mergeGetCommands(final Command currentCmd, commandCollector, expectedCommandType); } } - - private static final ThreadLocal BIN_SET_CMD_COLLECTOR_THREAD_LOCAL = new ThreadLocal(){ + + private static final ThreadLocal BIN_SET_CMD_COLLECTOR_THREAD_LOCAL = new ThreadLocal() { @Override protected BinarySetQCollector initialValue() { return new BinarySetQCollector(); } - + }; private final Command mergeSetCommands(final Command currentCmd, final Queue writeQueue, final Queue executingCmds, CommandType expectedCommandType, int sendBufferSize) { int mergeCount = 1; - final CommandCollector commandCollector = BIN_SET_CMD_COLLECTOR_THREAD_LOCAL.get().reset(); + final CommandCollector commandCollector = BIN_SET_CMD_COLLECTOR_THREAD_LOCAL + .get().reset(); currentCmd.setStatus(OperationStatus.WRITING); int totalBytes = currentCmd.getIoBuffer().remaining(); commandCollector.visit(currentCmd); @@ -594,26 +600,26 @@ private final Command mergeSetCommands(final Command currentCmd, } } - private static ThreadLocal TEXT_GET_CMD_COLLECTOR_THREAD_LOCAL = new ThreadLocal(){ + private static ThreadLocal TEXT_GET_CMD_COLLECTOR_THREAD_LOCAL = new ThreadLocal() { @Override - public KeyStringCollector initialValue(){ + public KeyStringCollector initialValue() { return new KeyStringCollector(); } }; - - private static ThreadLocal BIN_GET_CMD_COLLECTOR_THREAD_LOCAL = new ThreadLocal(){ + + private static ThreadLocal BIN_GET_CMD_COLLECTOR_THREAD_LOCAL = new ThreadLocal() { @Override - public BinaryGetQCollector initialValue(){ + public BinaryGetQCollector initialValue() { return new BinaryGetQCollector(); } }; - + private CommandCollector createGetCommandCollector() { switch (this.protocol) { - case Binary: - return BIN_GET_CMD_COLLECTOR_THREAD_LOCAL.get().reset(); - default: - return TEXT_GET_CMD_COLLECTOR_THREAD_LOCAL.get().reset(); + case Binary : + return BIN_GET_CMD_COLLECTOR_THREAD_LOCAL.get().reset(); + default : + return TEXT_GET_CMD_COLLECTOR_THREAD_LOCAL.get().reset(); } } @@ -624,7 +630,8 @@ private Command newMergedCommand(final Map mergeCommands, String resultKey = (String) commandCollector.getResult(); byte[] keyBytes = ByteUtils.getBytes(resultKey); - byte[] cmdBytes = commandType == CommandType.GET_ONE ? Constants.GET + byte[] cmdBytes = commandType == CommandType.GET_ONE + ? Constants.GET : Constants.GETS; final byte[] buf = new byte[cmdBytes.length + 3 + keyBytes.length]; ByteUtils.setArguments(buf, 0, cmdBytes, keyBytes); diff --git a/src/main/java/net/rubyeye/xmemcached/impl/OptimizerMBean.java b/src/main/java/net/rubyeye/xmemcached/impl/OptimizerMBean.java index dc022b11f..8847882e3 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/OptimizerMBean.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/OptimizerMBean.java @@ -22,7 +22,6 @@ */ package net.rubyeye.xmemcached.impl; - /** * OptimizerMBean,used for changing the optimizer's factor * @@ -42,5 +41,4 @@ public interface OptimizerMBean { public void setOptimizeMergeBuffer(boolean optimiezeMergeBuffer); - } diff --git a/src/main/java/net/rubyeye/xmemcached/impl/PHPMemcacheSessionLocator.java b/src/main/java/net/rubyeye/xmemcached/impl/PHPMemcacheSessionLocator.java index bc0c00895..fa56ec373 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/PHPMemcacheSessionLocator.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/PHPMemcacheSessionLocator.java @@ -21,15 +21,13 @@ import com.google.code.yanf4j.core.Session; /** - * Session locator base on hash(key) mod sessions.size(). Uses the PHP - * memcached hash strategy so it's easier to share data with PHP based - * clients. + * Session locator base on hash(key) mod sessions.size(). Uses the PHP memcached + * hash strategy so it's easier to share data with PHP based clients. * * @author aravind * */ -public class PHPMemcacheSessionLocator extends - AbstractMemcachedSessionLocator { +public class PHPMemcacheSessionLocator extends AbstractMemcachedSessionLocator { private HashAlgorithm hashAlgorithm; private transient volatile List sessions; @@ -48,7 +46,7 @@ public final void setHashAlgorighm(HashAlgorithm hashAlgorithm) { public final long getHash(int size, String key) { long hash = this.hashAlgorithm.hash(key); - hash = (hash >> 16) & 0x7fff; + hash = (hash >> 16) & 0x7fff; return hash % size; } diff --git a/src/main/java/net/rubyeye/xmemcached/impl/ReconnectRequest.java b/src/main/java/net/rubyeye/xmemcached/impl/ReconnectRequest.java index eaa29d834..8076eb2bb 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/ReconnectRequest.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/ReconnectRequest.java @@ -27,7 +27,6 @@ import net.rubyeye.xmemcached.utils.InetSocketAddressWrapper; - /** * A auto reconnect request,associating a socket address for reconnecting * @@ -36,86 +35,81 @@ */ public final class ReconnectRequest implements Delayed { - private InetSocketAddressWrapper inetSocketAddressWrapper; - private int tries; - - private static final long MIN_RECONNECT_INTERVAL = 1000; - - private static final long MAX_RECONNECT_INTERVAL = 60 * 1000; - - private volatile long nextReconnectTimestamp; - - - public ReconnectRequest(InetSocketAddressWrapper inetSocketAddressWrapper, int tries, long reconnectInterval) { - super(); - this.setInetSocketAddressWrapper(inetSocketAddressWrapper); - this.setTries(tries); // record reconnect times - reconnectInterval = this.normalInterval(reconnectInterval); - this.nextReconnectTimestamp = System.currentTimeMillis() + reconnectInterval; - } - - - private long normalInterval(long reconnectInterval) { - if (reconnectInterval < MIN_RECONNECT_INTERVAL) { - reconnectInterval = MIN_RECONNECT_INTERVAL; - } - if (reconnectInterval > MAX_RECONNECT_INTERVAL) { - reconnectInterval = MAX_RECONNECT_INTERVAL; - } - return reconnectInterval; - } - - - public long getDelay(TimeUnit unit) { - return unit.convert(this.nextReconnectTimestamp - System.currentTimeMillis(), TimeUnit.MILLISECONDS); - } - - - public int compareTo(Delayed o) { - ReconnectRequest other = (ReconnectRequest) o; - if (this.nextReconnectTimestamp > other.nextReconnectTimestamp) { - return 1; - } - else { - return -1; - } - } - - - /** - * Returns a reconnect socket address wrapper - * - * @see InetSocketAddressWrapper - * @return - */ - public final InetSocketAddressWrapper getInetSocketAddressWrapper() { - return this.inetSocketAddressWrapper; - } - - - public void updateNextReconnectTimeStamp(long interval) { - interval = this.normalInterval(interval); - this.nextReconnectTimestamp = System.currentTimeMillis() + interval; - } - - - public final void setInetSocketAddressWrapper(InetSocketAddressWrapper inetSocketAddressWrapper) { - this.inetSocketAddressWrapper = inetSocketAddressWrapper; - } - - - public final void setTries(int tries) { - this.tries = tries; - } - - - /** - * Returns retry times - * - * @return retry times,it is zero if it does not retry to connect - */ - public final int getTries() { - return this.tries; - } + private InetSocketAddressWrapper inetSocketAddressWrapper; + private int tries; + + private static final long MIN_RECONNECT_INTERVAL = 1000; + + private static final long MAX_RECONNECT_INTERVAL = 60 * 1000; + + private volatile long nextReconnectTimestamp; + + public ReconnectRequest(InetSocketAddressWrapper inetSocketAddressWrapper, + int tries, long reconnectInterval) { + super(); + this.setInetSocketAddressWrapper(inetSocketAddressWrapper); + this.setTries(tries); // record reconnect times + reconnectInterval = this.normalInterval(reconnectInterval); + this.nextReconnectTimestamp = System.currentTimeMillis() + + reconnectInterval; + } + + private long normalInterval(long reconnectInterval) { + if (reconnectInterval < MIN_RECONNECT_INTERVAL) { + reconnectInterval = MIN_RECONNECT_INTERVAL; + } + if (reconnectInterval > MAX_RECONNECT_INTERVAL) { + reconnectInterval = MAX_RECONNECT_INTERVAL; + } + return reconnectInterval; + } + + public long getDelay(TimeUnit unit) { + return unit.convert( + this.nextReconnectTimestamp - System.currentTimeMillis(), + TimeUnit.MILLISECONDS); + } + + public int compareTo(Delayed o) { + ReconnectRequest other = (ReconnectRequest) o; + if (this.nextReconnectTimestamp > other.nextReconnectTimestamp) { + return 1; + } else { + return -1; + } + } + + /** + * Returns a reconnect socket address wrapper + * + * @see InetSocketAddressWrapper + * @return + */ + public final InetSocketAddressWrapper getInetSocketAddressWrapper() { + return this.inetSocketAddressWrapper; + } + + public void updateNextReconnectTimeStamp(long interval) { + interval = this.normalInterval(interval); + this.nextReconnectTimestamp = System.currentTimeMillis() + interval; + } + + public final void setInetSocketAddressWrapper( + InetSocketAddressWrapper inetSocketAddressWrapper) { + this.inetSocketAddressWrapper = inetSocketAddressWrapper; + } + + public final void setTries(int tries) { + this.tries = tries; + } + + /** + * Returns retry times + * + * @return retry times,it is zero if it does not retry to connect + */ + public final int getTries() { + return this.tries; + } } \ No newline at end of file diff --git a/src/main/java/net/rubyeye/xmemcached/impl/RoundRobinMemcachedSessionLocator.java b/src/main/java/net/rubyeye/xmemcached/impl/RoundRobinMemcachedSessionLocator.java index 389582c44..7d903b23b 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/RoundRobinMemcachedSessionLocator.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/RoundRobinMemcachedSessionLocator.java @@ -18,8 +18,9 @@ * @author apple * */ -public class RoundRobinMemcachedSessionLocator implements - MemcachedSessionLocator { +public class RoundRobinMemcachedSessionLocator + implements + MemcachedSessionLocator { private transient volatile List sessions; private AtomicInteger sets = new AtomicInteger(0); diff --git a/src/main/java/net/rubyeye/xmemcached/monitor/Constants.java b/src/main/java/net/rubyeye/xmemcached/monitor/Constants.java index b5300fbac..3252f41b1 100644 --- a/src/main/java/net/rubyeye/xmemcached/monitor/Constants.java +++ b/src/main/java/net/rubyeye/xmemcached/monitor/Constants.java @@ -50,19 +50,19 @@ public class Constants { * Whether to enable jmx supports */ public static final String XMEMCACHED_JMX_ENABLE = "xmemcached.jmx.enable"; - public static final byte[] CRLF = { '\r', '\n' }; - public static final byte[] GET = { 'g', 'e', 't' }; - public static final byte[] GETS = { 'g', 'e', 't', 's' }; + public static final byte[] CRLF = {'\r', '\n'}; + public static final byte[] GET = {'g', 'e', 't'}; + public static final byte[] GETS = {'g', 'e', 't', 's'}; public static final byte SPACE = ' '; - public static final byte[] INCR = { 'i', 'n', 'c', 'r' }; - public static final byte[] DECR = { 'd', 'e', 'c', 'r' }; - public static final byte[] DELETE = { 'd', 'e', 'l', 'e', 't', 'e' }; - public static final byte[] TOUCH = { 't', 'o', 'u', 'c', 'h' }; + public static final byte[] INCR = {'i', 'n', 'c', 'r'}; + public static final byte[] DECR = {'d', 'e', 'c', 'r'}; + public static final byte[] DELETE = {'d', 'e', 'l', 'e', 't', 'e'}; + public static final byte[] TOUCH = {'t', 'o', 'u', 'c', 'h'}; /** * Max session read buffer size,758k */ public static final int MAX_SESSION_READ_BUFFER_SIZE = 768 * 1024; - public static final byte[] NO_REPLY = { 'n', 'o', 'r', 'e', 'p', 'l', 'y' }; + public static final byte[] NO_REPLY = {'n', 'o', 'r', 'e', 'p', 'l', 'y'}; /** * Client instance counter */ diff --git a/src/main/java/net/rubyeye/xmemcached/monitor/MemcachedClientNameHolder.java b/src/main/java/net/rubyeye/xmemcached/monitor/MemcachedClientNameHolder.java index 48d09381a..4355fdf0a 100644 --- a/src/main/java/net/rubyeye/xmemcached/monitor/MemcachedClientNameHolder.java +++ b/src/main/java/net/rubyeye/xmemcached/monitor/MemcachedClientNameHolder.java @@ -12,8 +12,8 @@ public class MemcachedClientNameHolder { public static void setName(String name) { cacheName.set(name); } - - public static String getName(){ + + public static String getName() { return cacheName.get(); } diff --git a/src/main/java/net/rubyeye/xmemcached/monitor/StatisticsHandler.java b/src/main/java/net/rubyeye/xmemcached/monitor/StatisticsHandler.java index 9e9ca0ee4..11a7c7780 100644 --- a/src/main/java/net/rubyeye/xmemcached/monitor/StatisticsHandler.java +++ b/src/main/java/net/rubyeye/xmemcached/monitor/StatisticsHandler.java @@ -39,15 +39,14 @@ public class StatisticsHandler implements StatisticsHandlerMBean { public StatisticsHandler() { buildCounterMap(); - XMemcachedMbeanServer.getInstance().registMBean( - this, + XMemcachedMbeanServer.getInstance().registMBean(this, this.getClass().getPackage().getName() + ":type=" + this.getClass().getSimpleName() + "-" + MemcachedClientNameHolder.getName()); } - private boolean statistics = Boolean.valueOf(System.getProperty( - Constants.XMEMCACHED_STATISTICS_ENABLE, "false")); + private boolean statistics = Boolean.valueOf(System + .getProperty(Constants.XMEMCACHED_STATISTICS_ENABLE, "false")); private void buildCounterMap() { if (this.statistics) { diff --git a/src/main/java/net/rubyeye/xmemcached/monitor/StatisticsHandlerMBean.java b/src/main/java/net/rubyeye/xmemcached/monitor/StatisticsHandlerMBean.java index a42260d33..af6d45613 100644 --- a/src/main/java/net/rubyeye/xmemcached/monitor/StatisticsHandlerMBean.java +++ b/src/main/java/net/rubyeye/xmemcached/monitor/StatisticsHandlerMBean.java @@ -58,9 +58,10 @@ public interface StatisticsHandlerMBean { public boolean isStatistics(); public void setStatistics(boolean statistics); - + /** * Reset the statistics + * * @since 1.3.9 */ public void resetStats(); diff --git a/src/main/java/net/rubyeye/xmemcached/monitor/XMemcachedMbeanServer.java b/src/main/java/net/rubyeye/xmemcached/monitor/XMemcachedMbeanServer.java index ec152a18c..b9cb93330 100644 --- a/src/main/java/net/rubyeye/xmemcached/monitor/XMemcachedMbeanServer.java +++ b/src/main/java/net/rubyeye/xmemcached/monitor/XMemcachedMbeanServer.java @@ -90,12 +90,12 @@ private void initialize() { } String host = System.getProperty("hostName", hostName); try { - boolean enableJMX = Boolean.parseBoolean(System.getProperty( - Constants.XMEMCACHED_JMX_ENABLE, "false")); + boolean enableJMX = Boolean.parseBoolean(System + .getProperty(Constants.XMEMCACHED_JMX_ENABLE, "false")); if (enableJMX) { mbserver = ManagementFactory.getPlatformMBeanServer(); - int port = Integer.parseInt(System.getProperty( - Constants.XMEMCACHED_RMI_PORT, "7077")); + int port = Integer.parseInt(System + .getProperty(Constants.XMEMCACHED_RMI_PORT, "7077")); String rmiName = System.getProperty( Constants.XMEMCACHED_RMI_NAME, "xmemcachedServer"); Registry registry = null; @@ -109,8 +109,8 @@ private void initialize() { registry = LocateRegistry.createRegistry(port); } registry.list(); - String serverURL = "service:jmx:rmi:///jndi/rmi://" + host - + ":" + port + "/" + rmiName; + String serverURL = "service:jmx:rmi:///jndi/rmi://" + host + ":" + + port + "/" + rmiName; JMXServiceURL url = new JMXServiceURL(serverURL); connectorServer = JMXConnectorServerFactory .newJMXConnectorServer(url, null, mbserver); @@ -120,10 +120,8 @@ private void initialize() { public void run() { try { isHutdownHookCalled = true; - if (connectorServer - .isActive()) { - connectorServer - .stop(); + if (connectorServer.isActive()) { + connectorServer.stop(); log.warn("JMXConnector stop"); } } catch (IOException e) { @@ -132,7 +130,7 @@ public void run() { } } }; - + Runtime.getRuntime().addShutdownHook(shutdownHookThread); log.warn("jmx url: " + serverURL); } diff --git a/src/main/java/net/rubyeye/xmemcached/networking/ClosedMemcachedSession.java b/src/main/java/net/rubyeye/xmemcached/networking/ClosedMemcachedSession.java index f804274fd..27af22c43 100644 --- a/src/main/java/net/rubyeye/xmemcached/networking/ClosedMemcachedSession.java +++ b/src/main/java/net/rubyeye/xmemcached/networking/ClosedMemcachedSession.java @@ -5,7 +5,7 @@ import net.rubyeye.xmemcached.utils.InetSocketAddressWrapper; public interface ClosedMemcachedSession extends Session { - + public void setAllowReconnect(boolean allow); public boolean isAllowReconnect(); diff --git a/src/main/java/net/rubyeye/xmemcached/transcoders/BaseSerializingTranscoder.java b/src/main/java/net/rubyeye/xmemcached/transcoders/BaseSerializingTranscoder.java index bf1ddcc1c..3a5578f8b 100644 --- a/src/main/java/net/rubyeye/xmemcached/transcoders/BaseSerializingTranscoder.java +++ b/src/main/java/net/rubyeye/xmemcached/transcoders/BaseSerializingTranscoder.java @@ -21,13 +21,16 @@ private XmcObjectInputStream(InputStream in) throws IOException { } @Override - protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { - try { - //When class is not found,try to load it from context class loader. - return super.resolveClass(desc); - } catch (ClassNotFoundException e) { - return Thread.currentThread().getContextClassLoader().loadClass(desc.getName()); - } + protected Class resolveClass(ObjectStreamClass desc) + throws IOException, ClassNotFoundException { + try { + // When class is not found,try to load it from context class + // loader. + return super.resolveClass(desc); + } catch (ClassNotFoundException e) { + return Thread.currentThread().getContextClassLoader() + .loadClass(desc.getName()); + } } } @@ -108,15 +111,16 @@ protected Object deserialize(byte[] in) { try { if (in != null) { bis = new ByteArrayInputStream(in); - is = new XmcObjectInputStream(bis); - rv = is.readObject(); + is = new XmcObjectInputStream(bis); + rv = is.readObject(); } } catch (IOException e) { log.error("Caught IOException decoding " + in.length + " bytes of data", e); } catch (ClassNotFoundException e) { - log.error("Caught CNFE decoding " + in.length + " bytes of data", e); + log.error("Caught CNFE decoding " + in.length + " bytes of data", + e); } finally { if (is != null) { try { @@ -141,12 +145,12 @@ protected Object deserialize(byte[] in) { */ public final byte[] compress(byte[] in) { switch (this.compressMode) { - case GZIP: - return gzipCompress(in); - case ZIP: - return zipCompress(in); - default: - return gzipCompress(in); + case GZIP : + return gzipCompress(in); + case ZIP : + return zipCompress(in); + default : + return gzipCompress(in); } } @@ -215,12 +219,12 @@ private static byte[] gzipCompress(byte[] in) { */ protected byte[] decompress(byte[] in) { switch (this.compressMode) { - case GZIP: - return gzipDecompress(in); - case ZIP: - return zipDecompress(in); - default: - return gzipDecompress(in); + case GZIP : + return gzipDecompress(in); + case ZIP : + return zipDecompress(in); + default : + return gzipDecompress(in); } } @@ -243,7 +247,7 @@ private byte[] zipDecompress(byte[] in) { } catch (IOException e) { log.error("Failed to decompress data", e); - //baos = null; + // baos = null; } finally { try { is.close(); diff --git a/src/main/java/net/rubyeye/xmemcached/transcoders/CachedData.java b/src/main/java/net/rubyeye/xmemcached/transcoders/CachedData.java index 78ffe73ad..fec2dbc06 100644 --- a/src/main/java/net/rubyeye/xmemcached/transcoders/CachedData.java +++ b/src/main/java/net/rubyeye/xmemcached/transcoders/CachedData.java @@ -20,14 +20,14 @@ public final class CachedData { private int capacity = -1; protected int size = 0; - - //cache decoded object. + + // cache decoded object. public volatile Object decodedObject; - - //padding fields - public long p1,p2,p3,p4; + + // padding fields + public long p1, p2, p3, p4; public int p5; - + protected byte[] data; public final int getSize() { diff --git a/src/main/java/net/rubyeye/xmemcached/transcoders/CompressionMode.java b/src/main/java/net/rubyeye/xmemcached/transcoders/CompressionMode.java index 977aae204..59f9c6249 100644 --- a/src/main/java/net/rubyeye/xmemcached/transcoders/CompressionMode.java +++ b/src/main/java/net/rubyeye/xmemcached/transcoders/CompressionMode.java @@ -7,12 +7,12 @@ * */ public enum CompressionMode { - /** - * Gzip mode - */ - GZIP, - /** - * Zip mode - */ - ZIP + /** + * Gzip mode + */ + GZIP, + /** + * Zip mode + */ + ZIP } diff --git a/src/main/java/net/rubyeye/xmemcached/transcoders/IntegerTranscoder.java b/src/main/java/net/rubyeye/xmemcached/transcoders/IntegerTranscoder.java index 4c655febb..1ca1fdf48 100644 --- a/src/main/java/net/rubyeye/xmemcached/transcoders/IntegerTranscoder.java +++ b/src/main/java/net/rubyeye/xmemcached/transcoders/IntegerTranscoder.java @@ -34,8 +34,8 @@ public CachedData encode(java.lang.Integer l) { } return new CachedData(flags, b, b.length, -1); } - return new CachedData(SerializingTranscoder.SPECIAL_INT, this.tu - .encodeInt(l)); + return new CachedData(SerializingTranscoder.SPECIAL_INT, + this.tu.encodeInt(l)); } public Integer decode(CachedData d) { diff --git a/src/main/java/net/rubyeye/xmemcached/transcoders/LongTranscoder.java b/src/main/java/net/rubyeye/xmemcached/transcoders/LongTranscoder.java index 015530a52..55acfdfad 100644 --- a/src/main/java/net/rubyeye/xmemcached/transcoders/LongTranscoder.java +++ b/src/main/java/net/rubyeye/xmemcached/transcoders/LongTranscoder.java @@ -39,7 +39,8 @@ public CachedData encode(java.lang.Long l) { } return new CachedData(flags, b, b.length, -1); } - return new CachedData(SerializingTranscoder.SPECIAL_LONG, this.tu.encodeLong(l)); + return new CachedData(SerializingTranscoder.SPECIAL_LONG, + this.tu.encodeLong(l)); } public Long decode(CachedData d) { diff --git a/src/main/java/net/rubyeye/xmemcached/transcoders/PrimitiveTypeTranscoder.java b/src/main/java/net/rubyeye/xmemcached/transcoders/PrimitiveTypeTranscoder.java index d7a3ae7e0..fc37af940 100644 --- a/src/main/java/net/rubyeye/xmemcached/transcoders/PrimitiveTypeTranscoder.java +++ b/src/main/java/net/rubyeye/xmemcached/transcoders/PrimitiveTypeTranscoder.java @@ -1,7 +1,10 @@ package net.rubyeye.xmemcached.transcoders; -public abstract class PrimitiveTypeTranscoder extends - BaseSerializingTranscoder implements Transcoder { +public abstract class PrimitiveTypeTranscoder + extends + BaseSerializingTranscoder + implements + Transcoder { protected final TranscoderUtils tu = new TranscoderUtils(true); protected boolean primitiveAsString; diff --git a/src/main/java/net/rubyeye/xmemcached/transcoders/SerializingTranscoder.java b/src/main/java/net/rubyeye/xmemcached/transcoders/SerializingTranscoder.java index ad8a102f9..6a7ca3d63 100644 --- a/src/main/java/net/rubyeye/xmemcached/transcoders/SerializingTranscoder.java +++ b/src/main/java/net/rubyeye/xmemcached/transcoders/SerializingTranscoder.java @@ -7,8 +7,9 @@ /** * Transcoder that serializes and compresses objects. */ -public class SerializingTranscoder extends BaseSerializingTranscoder implements - Transcoder { +public class SerializingTranscoder extends BaseSerializingTranscoder + implements + Transcoder { public void setPackZeros(boolean packZeros) { this.transcoderUtils.setPackZeros(packZeros); @@ -92,7 +93,8 @@ public final Object decode(CachedData d) { return obj; } - protected final Object decode0(CachedData cachedData,byte[] data, int flags) { + protected final Object decode0(CachedData cachedData, byte[] data, + int flags) { Object rv = null; if ((cachedData.flag & SERIALIZED) != 0 && data != null) { rv = deserialize(data); @@ -104,38 +106,39 @@ protected final Object decode0(CachedData cachedData,byte[] data, int flags) { } if (flags != 0 && data != null) { switch (flags) { - case SPECIAL_BOOLEAN: - rv = Boolean.valueOf(this.transcoderUtils - .decodeBoolean(data)); - break; - case SPECIAL_INT: - rv = Integer.valueOf(this.transcoderUtils.decodeInt(data)); - break; - case SPECIAL_LONG: - rv = Long.valueOf(this.transcoderUtils.decodeLong(data)); - break; - case SPECIAL_BYTE: - rv = Byte.valueOf(this.transcoderUtils.decodeByte(data)); - break; - case SPECIAL_FLOAT: - rv = new Float(Float.intBitsToFloat(this.transcoderUtils - .decodeInt(data))); - break; - case SPECIAL_DOUBLE: - rv = new Double(Double - .longBitsToDouble(this.transcoderUtils - .decodeLong(data))); - break; - case SPECIAL_DATE: - rv = new Date(this.transcoderUtils.decodeLong(data)); - break; - case SPECIAL_BYTEARRAY: - rv = data; - break; - default: - log - .warn(String.format("Undecodeable with flags %x", - flags)); + case SPECIAL_BOOLEAN : + rv = Boolean.valueOf( + this.transcoderUtils.decodeBoolean(data)); + break; + case SPECIAL_INT : + rv = Integer + .valueOf(this.transcoderUtils.decodeInt(data)); + break; + case SPECIAL_LONG : + rv = Long + .valueOf(this.transcoderUtils.decodeLong(data)); + break; + case SPECIAL_BYTE : + rv = Byte + .valueOf(this.transcoderUtils.decodeByte(data)); + break; + case SPECIAL_FLOAT : + rv = new Float(Float.intBitsToFloat( + this.transcoderUtils.decodeInt(data))); + break; + case SPECIAL_DOUBLE : + rv = new Double(Double.longBitsToDouble( + this.transcoderUtils.decodeLong(data))); + break; + case SPECIAL_DATE : + rv = new Date(this.transcoderUtils.decodeLong(data)); + break; + case SPECIAL_BYTEARRAY : + rv = data; + break; + default : + log.warn(String.format("Undecodeable with flags %x", + flags)); } } else { rv = decodeString(data); @@ -189,16 +192,16 @@ public final CachedData encode(Object o) { if (this.primitiveAsString) { b = encodeString(o.toString()); } else { - b = this.transcoderUtils.encodeInt(Float - .floatToRawIntBits((Float) o)); + b = this.transcoderUtils + .encodeInt(Float.floatToRawIntBits((Float) o)); } flags |= SPECIAL_FLOAT; } else if (o instanceof Double) { if (this.primitiveAsString) { b = encodeString(o.toString()); } else { - b = this.transcoderUtils.encodeLong(Double - .doubleToRawLongBits((Double) o)); + b = this.transcoderUtils + .encodeLong(Double.doubleToRawLongBits((Double) o)); } flags |= SPECIAL_DOUBLE; } else if (o instanceof byte[]) { diff --git a/src/main/java/net/rubyeye/xmemcached/transcoders/TokyoTyrantTranscoder.java b/src/main/java/net/rubyeye/xmemcached/transcoders/TokyoTyrantTranscoder.java index ea2de6a39..e93eb51ed 100644 --- a/src/main/java/net/rubyeye/xmemcached/transcoders/TokyoTyrantTranscoder.java +++ b/src/main/java/net/rubyeye/xmemcached/transcoders/TokyoTyrantTranscoder.java @@ -53,8 +53,8 @@ public final Object decode(CachedData d) { System.arraycopy(compositeData, 0, flagBytes, 0, 4); System.arraycopy(compositeData, 4, realData, 0, compositeData.length - 4); - int flag = serializingTranscoder.getTranscoderUtils().decodeInt( - flagBytes); + int flag = serializingTranscoder.getTranscoderUtils() + .decodeInt(flagBytes); d.setFlag(flag); if ((flag & SerializingTranscoder.COMPRESSED) != 0) { realData = serializingTranscoder.decompress(realData); @@ -62,11 +62,9 @@ public final Object decode(CachedData d) { flag = flag & SerializingTranscoder.SPECIAL_MASK; return serializingTranscoder.decode0(d, realData, flag); } - - public void setCompressionMode(CompressionMode compressMode) { - this.serializingTranscoder.setCompressionMode(compressMode); + this.serializingTranscoder.setCompressionMode(compressMode); } public final CachedData encode(Object o) { diff --git a/src/main/java/net/rubyeye/xmemcached/transcoders/Transcoder.java b/src/main/java/net/rubyeye/xmemcached/transcoders/Transcoder.java index 2971fb383..ac420ec1d 100644 --- a/src/main/java/net/rubyeye/xmemcached/transcoders/Transcoder.java +++ b/src/main/java/net/rubyeye/xmemcached/transcoders/Transcoder.java @@ -41,24 +41,28 @@ public interface Transcoder { public void setPackZeros(boolean packZeros); /** * Set compression threshold in bytes + * * @param to */ public void setCompressionThreshold(int to); /** * Returns if client stores primitive type as string. + * * @return */ public boolean isPrimitiveAsString(); /** * Returns if transcoder packs zero. + * * @return */ public boolean isPackZeros(); - + /** * Set compress mode,default is ZIP + * * @see CompressionMode * @param compressMode */ diff --git a/src/main/java/net/rubyeye/xmemcached/transcoders/TranscoderUtils.java b/src/main/java/net/rubyeye/xmemcached/transcoders/TranscoderUtils.java index 0696190de..227ec0d99 100644 --- a/src/main/java/net/rubyeye/xmemcached/transcoders/TranscoderUtils.java +++ b/src/main/java/net/rubyeye/xmemcached/transcoders/TranscoderUtils.java @@ -73,7 +73,7 @@ public final int decodeInt(byte[] in) { } public final byte[] encodeByte(byte in) { - return new byte[] { in }; + return new byte[]{in}; } public final byte decodeByte(byte[] in) { diff --git a/src/main/java/net/rubyeye/xmemcached/transcoders/WhalinTranscoder.java b/src/main/java/net/rubyeye/xmemcached/transcoders/WhalinTranscoder.java index f0cba0e84..469155415 100644 --- a/src/main/java/net/rubyeye/xmemcached/transcoders/WhalinTranscoder.java +++ b/src/main/java/net/rubyeye/xmemcached/transcoders/WhalinTranscoder.java @@ -5,8 +5,9 @@ /** * Transcoder that provides compatibility with Greg Whalin's memcached client. */ -public class WhalinTranscoder extends BaseSerializingTranscoder implements - Transcoder { +public class WhalinTranscoder extends BaseSerializingTranscoder + implements + Transcoder { public static final int SPECIAL_BYTE = 1; public static final int SPECIAL_BOOLEAN = 8192; @@ -83,48 +84,50 @@ public Object decode(CachedData d) { } } switch (f) { - case SPECIAL_BOOLEAN: - rv = Boolean.valueOf(this.decodeBoolean(data)); - break; - case SPECIAL_INT: - rv = Integer.valueOf(this.tu.decodeInt(data)); - break; - case SPECIAL_SHORT: - rv = Short.valueOf((short) this.tu.decodeInt(data)); - break; - case SPECIAL_LONG: - rv = Long.valueOf(this.tu.decodeLong(data)); - break; - case SPECIAL_DATE: - rv = new Date(this.tu.decodeLong(data)); - break; - case SPECIAL_BYTE: - rv = Byte.valueOf(this.tu.decodeByte(data)); - break; - case SPECIAL_FLOAT: - rv = new Float(Float.intBitsToFloat(this.tu.decodeInt(data))); - break; - case SPECIAL_DOUBLE: - rv = new Double(Double.longBitsToDouble(this.tu - .decodeLong(data))); - break; - case SPECIAL_BYTEARRAY: - rv = data; - break; - case SPECIAL_STRING: - rv = decodeString(data); - break; - case SPECIAL_STRINGBUFFER: - rv = new StringBuffer(decodeString(data)); - break; - case SPECIAL_STRINGBUILDER: - rv = new StringBuilder(decodeString(data)); - break; - case SPECIAL_CHARACTER: - rv = decodeCharacter(data); - break; - default: - log.warn(String.format("Cannot handle data with flags %x", f)); + case SPECIAL_BOOLEAN : + rv = Boolean.valueOf(this.decodeBoolean(data)); + break; + case SPECIAL_INT : + rv = Integer.valueOf(this.tu.decodeInt(data)); + break; + case SPECIAL_SHORT : + rv = Short.valueOf((short) this.tu.decodeInt(data)); + break; + case SPECIAL_LONG : + rv = Long.valueOf(this.tu.decodeLong(data)); + break; + case SPECIAL_DATE : + rv = new Date(this.tu.decodeLong(data)); + break; + case SPECIAL_BYTE : + rv = Byte.valueOf(this.tu.decodeByte(data)); + break; + case SPECIAL_FLOAT : + rv = new Float( + Float.intBitsToFloat(this.tu.decodeInt(data))); + break; + case SPECIAL_DOUBLE : + rv = new Double( + Double.longBitsToDouble(this.tu.decodeLong(data))); + break; + case SPECIAL_BYTEARRAY : + rv = data; + break; + case SPECIAL_STRING : + rv = decodeString(data); + break; + case SPECIAL_STRINGBUFFER : + rv = new StringBuffer(decodeString(data)); + break; + case SPECIAL_STRINGBUILDER : + rv = new StringBuilder(decodeString(data)); + break; + case SPECIAL_CHARACTER : + rv = decodeCharacter(data); + break; + default : + log.warn(String.format("Cannot handle data with flags %x", + f)); } } return rv; @@ -215,21 +218,18 @@ public CachedData encode(Object o) { byte[] compressed = compress(b); if (compressed.length < b.length) { if (log.isDebugEnabled()) { - log - .debug(String.format("Compressed %s from %d to %d", - o.getClass().getName(), b.length, - compressed.length)); + log.debug(String.format("Compressed %s from %d to %d", + o.getClass().getName(), b.length, + compressed.length)); } b = compressed; flags |= COMPRESSED; } else { if (log.isDebugEnabled()) { - log - .debug(String - .format( - "Compression increased the size of %s from %d to %d", - o.getClass().getName(), b.length, - compressed.length)); + log.debug(String.format( + "Compression increased the size of %s from %d to %d", + o.getClass().getName(), b.length, + compressed.length)); } } } diff --git a/src/main/java/net/rubyeye/xmemcached/transcoders/WhalinV1Transcoder.java b/src/main/java/net/rubyeye/xmemcached/transcoders/WhalinV1Transcoder.java index da9ab46e9..62cd4e4a6 100644 --- a/src/main/java/net/rubyeye/xmemcached/transcoders/WhalinV1Transcoder.java +++ b/src/main/java/net/rubyeye/xmemcached/transcoders/WhalinV1Transcoder.java @@ -10,8 +10,9 @@ * @author bpartensky * @since Oct 16, 2008 */ -public class WhalinV1Transcoder extends BaseSerializingTranscoder implements - Transcoder { +public class WhalinV1Transcoder extends BaseSerializingTranscoder + implements + Transcoder { public static final int SPECIAL_BYTE = 1; public static final int SPECIAL_BOOLEAN = 2; @@ -28,7 +29,6 @@ public class WhalinV1Transcoder extends BaseSerializingTranscoder implements public static final int COMPRESSED = 2; public static final int SERIALIZED = 8; - public void setPackZeros(boolean packZeros) { throw new UnsupportedOperationException(); @@ -45,7 +45,6 @@ public boolean isPrimitiveAsString() { return false; } - public CachedData encode(Object o) { byte[] b = null; int flags = 0; @@ -83,15 +82,14 @@ public CachedData encode(Object o) { if (b.length > this.compressionThreshold) { byte[] compressed = compress(b); if (compressed.length < b.length) { - log.debug(String.format("Compressed %s from %d to %d", o - .getClass().getName(), b.length, compressed.length)); + log.debug(String.format("Compressed %s from %d to %d", + o.getClass().getName(), b.length, compressed.length)); b = compressed; flags |= COMPRESSED; } else { log.debug(String.format( - "Compression increased the size of %s from %d to %d", o - .getClass().getName(), b.length, - compressed.length)); + "Compression increased the size of %s from %d to %d", + o.getClass().getName(), b.length, compressed.length)); } } return new CachedData(flags, b); @@ -108,44 +106,45 @@ public Object decode(CachedData d) { } else { int f = data[0]; switch (f) { - case SPECIAL_BOOLEAN: - rv = decodeBoolean(data); - break; - case SPECIAL_INTEGER: - rv = decodeInteger(data); - break; - case SPECIAL_SHORT: - rv = decodeShort(data); - break; - case SPECIAL_LONG: - rv = decodeLong(data); - break; - case SPECIAL_DATE: - rv = new Date(decodeLong(data)); - break; - case SPECIAL_BYTE: - rv = decodeByte(data); - break; - case SPECIAL_FLOAT: - rv = decodeFloat(data); - break; - case SPECIAL_DOUBLE: - rv = decodeDouble(data); - break; - case SPECIAL_STRING: - rv = decodeW1String(data); - break; - case SPECIAL_STRINGBUFFER: - rv = new StringBuffer(decodeW1String(data)); - break; - case SPECIAL_STRINGBUILDER: - rv = new StringBuilder(decodeW1String(data)); - break; - case SPECIAL_CHARACTER: - rv = decodeCharacter(data); - break; - default: - log.warn(String.format("Cannot handle data with flags %x", f)); + case SPECIAL_BOOLEAN : + rv = decodeBoolean(data); + break; + case SPECIAL_INTEGER : + rv = decodeInteger(data); + break; + case SPECIAL_SHORT : + rv = decodeShort(data); + break; + case SPECIAL_LONG : + rv = decodeLong(data); + break; + case SPECIAL_DATE : + rv = new Date(decodeLong(data)); + break; + case SPECIAL_BYTE : + rv = decodeByte(data); + break; + case SPECIAL_FLOAT : + rv = decodeFloat(data); + break; + case SPECIAL_DOUBLE : + rv = decodeDouble(data); + break; + case SPECIAL_STRING : + rv = decodeW1String(data); + break; + case SPECIAL_STRINGBUFFER : + rv = new StringBuffer(decodeW1String(data)); + break; + case SPECIAL_STRINGBUILDER : + rv = new StringBuilder(decodeW1String(data)); + break; + case SPECIAL_CHARACTER : + rv = decodeCharacter(data); + break; + default : + log.warn(String.format("Cannot handle data with flags %x", + f)); } } return rv; diff --git a/src/main/java/net/rubyeye/xmemcached/utils/AddrUtil.java b/src/main/java/net/rubyeye/xmemcached/utils/AddrUtil.java index a9881b0a5..532f4710b 100644 --- a/src/main/java/net/rubyeye/xmemcached/utils/AddrUtil.java +++ b/src/main/java/net/rubyeye/xmemcached/utils/AddrUtil.java @@ -35,12 +35,11 @@ public class AddrUtil { /** - * Split a string in the form of - * "host1:port1,host2:port2 host3:port3,host4:port4" into a Map of - * InetSocketAddress instances suitable for instantiating a - * MemcachedClient,map's key is the main memcached node,and value is the - * standby node for main node. Note that colon-delimited IPv6 is also supported. For - * example: ::1:11211 + * Split a string in the form of "host1:port1,host2:port2 + * host3:port3,host4:port4" into a Map of InetSocketAddress instances + * suitable for instantiating a MemcachedClient,map's key is the main + * memcached node,and value is the standby node for main node. Note that + * colon-delimited IPv6 is also supported. For example: ::1:11211 * * @param s * @return @@ -51,17 +50,17 @@ public static Map getAddressMap( throw new NullPointerException("Null host list"); } if (s.trim().equals("")) { - throw new IllegalArgumentException("No hosts in list: ``" + s - + "''"); + throw new IllegalArgumentException( + "No hosts in list: ``" + s + "''"); } - s=s.trim(); + s = s.trim(); Map result = new LinkedHashMap(); for (String hosts : s.split(" ")) { String[] nodes = hosts.split(","); if (nodes.length < 1) { - throw new IllegalArgumentException("Invalid server ``" + hosts - + "'' in list: " + s); + throw new IllegalArgumentException( + "Invalid server ``" + hosts + "'' in list: " + s); } String mainHost = nodes[0].trim(); InetSocketAddress mainAddress = getInetSocketAddress(s, mainHost); @@ -82,15 +81,15 @@ private static InetSocketAddress getInetSocketAddress(String s, String mainHost) { int finalColon = mainHost.lastIndexOf(':'); if (finalColon < 1) { - throw new IllegalArgumentException("Invalid server ``" + mainHost - + "'' in list: " + s); + throw new IllegalArgumentException( + "Invalid server ``" + mainHost + "'' in list: " + s); } String hostPart = mainHost.substring(0, finalColon).trim(); String portNum = mainHost.substring(finalColon + 1).trim(); - InetSocketAddress mainAddress = new InetSocketAddress(hostPart, Integer - .parseInt(portNum)); + InetSocketAddress mainAddress = new InetSocketAddress(hostPart, + Integer.parseInt(portNum)); return mainAddress; } @@ -105,8 +104,8 @@ public static List getAddresses(String s) { throw new NullPointerException("Null host list"); } if (s.trim().equals("")) { - throw new IllegalArgumentException("No hosts in list: ``" + s - + "''"); + throw new IllegalArgumentException( + "No hosts in list: ``" + s + "''"); } s = s.trim(); ArrayList addrs = new ArrayList(); @@ -114,16 +113,15 @@ public static List getAddresses(String s) { for (String hoststuff : s.split(" ")) { int finalColon = hoststuff.lastIndexOf(':'); if (finalColon < 1) { - throw new IllegalArgumentException("Invalid server ``" - + hoststuff + "'' in list: " + s); + throw new IllegalArgumentException( + "Invalid server ``" + hoststuff + "'' in list: " + s); } String hostPart = hoststuff.substring(0, finalColon).trim(); String portNum = hoststuff.substring(finalColon + 1).trim(); - addrs - .add(new InetSocketAddress(hostPart, Integer - .parseInt(portNum))); + addrs.add( + new InetSocketAddress(hostPart, Integer.parseInt(portNum))); } assert !addrs.isEmpty() : "No addrs found"; return addrs; @@ -134,14 +132,14 @@ public static InetSocketAddress getOneAddress(String server) { throw new NullPointerException("Null host"); } if (server.trim().equals("")) { - throw new IllegalArgumentException("No hosts in: ``" + server - + "''"); + throw new IllegalArgumentException( + "No hosts in: ``" + server + "''"); } server = server.trim(); int finalColon = server.lastIndexOf(':'); if (finalColon < 1) { - throw new IllegalArgumentException("Invalid server ``" + server - + "''"); + throw new IllegalArgumentException( + "Invalid server ``" + server + "''"); } String hostPart = server.substring(0, finalColon).trim(); @@ -155,7 +153,7 @@ public static InetSocketAddress getOneAddress(String server) { * @since 2.0.1 */ public static boolean isEnableShutDownHook() { - return Boolean.valueOf(System.getProperty( - "xmemcached.shutdown.hook.enable", "false")); + return Boolean.valueOf( + System.getProperty("xmemcached.shutdown.hook.enable", "false")); } } diff --git a/src/main/java/net/rubyeye/xmemcached/utils/ByteUtils.java b/src/main/java/net/rubyeye/xmemcached/utils/ByteUtils.java index f5b8454ef..14fefe2b7 100644 --- a/src/main/java/net/rubyeye/xmemcached/utils/ByteUtils.java +++ b/src/main/java/net/rubyeye/xmemcached/utils/ByteUtils.java @@ -37,8 +37,8 @@ public final class ByteUtils { public static final ByteBuffer SPLIT = ByteBuffer.wrap(Constants.CRLF); public static final boolean ENABLE_CACHED_STRING_BYTES = Boolean - .valueOf(System.getProperty( - "xmemcached.string.bytes.cached.enable", "false")); + .valueOf(System.getProperty("xmemcached.string.bytes.cached.enable", + "false")); /** * if it is testing,check key argument even if use binary protocol. The user * must never change this value at all. @@ -204,39 +204,39 @@ public static void setProtocol(Protocol protocol) { public static final int normalizeCapacity(int requestedCapacity) { switch (requestedCapacity) { - case 0: - case 1 << 0: - case 1 << 1: - case 1 << 2: - case 1 << 3: - case 1 << 4: - case 1 << 5: - case 1 << 6: - case 1 << 7: - case 1 << 8: - case 1 << 9: - case 1 << 10: - case 1 << 11: - case 1 << 12: - case 1 << 13: - case 1 << 14: - case 1 << 15: - case 1 << 16: - case 1 << 17: - case 1 << 18: - case 1 << 19: - case 1 << 21: - case 1 << 22: - case 1 << 23: - case 1 << 24: - case 1 << 25: - case 1 << 26: - case 1 << 27: - case 1 << 28: - case 1 << 29: - case 1 << 30: - case Integer.MAX_VALUE: - return requestedCapacity; + case 0 : + case 1 << 0 : + case 1 << 1 : + case 1 << 2 : + case 1 << 3 : + case 1 << 4 : + case 1 << 5 : + case 1 << 6 : + case 1 << 7 : + case 1 << 8 : + case 1 << 9 : + case 1 << 10 : + case 1 << 11 : + case 1 << 12 : + case 1 << 13 : + case 1 << 14 : + case 1 << 15 : + case 1 << 16 : + case 1 << 17 : + case 1 << 18 : + case 1 << 19 : + case 1 << 21 : + case 1 << 22 : + case 1 << 23 : + case 1 << 24 : + case 1 << 25 : + case 1 << 26 : + case 1 << 27 : + case 1 << 28 : + case 1 << 29 : + case 1 << 30 : + case Integer.MAX_VALUE : + return requestedCapacity; } int newCapacity = 1; @@ -269,8 +269,8 @@ public static final String nextLine(ByteBuffer buffer) { return null; } - int index = MemcachedDecoder.SPLIT_MATCHER - .matchFirst(com.google.code.yanf4j.buffer.IoBuffer.wrap(buffer)); + int index = MemcachedDecoder.SPLIT_MATCHER.matchFirst( + com.google.code.yanf4j.buffer.IoBuffer.wrap(buffer)); if (index >= 0) { int limit = buffer.limit(); buffer.limit(index); @@ -293,8 +293,8 @@ public static String getString(byte[] bytes) { } public static void byte2hex(byte b, StringBuffer buf) { - char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'A', 'B', 'C', 'D', 'E', 'F' }; + char[] hexChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F'}; int high = ((b & 0xf0) >> 4); int low = (b & 0x0f); buf.append(hexChars[high]); @@ -403,12 +403,12 @@ static void getBytes(int i, int index, byte[] buf) { /** * All possible chars for representing a number as a String */ - final static byte[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', + final static byte[] digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', - 'z' }; + 'z'}; - final static byte[] DigitTens = { '0', '0', '0', '0', '0', '0', '0', '0', + final static byte[] DigitTens = {'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', '3', '3', '3', '3', '3', '3', '3', '3', '3', '3', '4', '4', '4', '4', '4', '4', '4', @@ -416,9 +416,9 @@ static void getBytes(int i, int index, byte[] buf) { '6', '6', '6', '6', '6', '6', '6', '6', '6', '6', '7', '7', '7', '7', '7', '7', '7', '7', '7', '7', '8', '8', '8', '8', '8', '8', '8', '8', '8', '8', '9', '9', '9', '9', '9', '9', '9', '9', '9', - '9', }; + '9',}; - final static byte[] DigitOnes = { '0', '1', '2', '3', '4', '5', '6', '7', + final static byte[] DigitOnes = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', @@ -426,10 +426,10 @@ static void getBytes(int i, int index, byte[] buf) { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', - '9', }; + '9',}; - final static int[] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999, - 99999999, 999999999, Integer.MAX_VALUE }; + final static int[] sizeTable = {9, 99, 999, 9999, 99999, 999999, 9999999, + 99999999, 999999999, Integer.MAX_VALUE}; // Requires positive x public static final int stringSize(int x) { diff --git a/src/main/java/net/rubyeye/xmemcached/utils/CachedString.java b/src/main/java/net/rubyeye/xmemcached/utils/CachedString.java index 431c08f92..423fd5086 100644 --- a/src/main/java/net/rubyeye/xmemcached/utils/CachedString.java +++ b/src/main/java/net/rubyeye/xmemcached/utils/CachedString.java @@ -40,8 +40,7 @@ static public void clearCache(ReferenceQueue rq, ConcurrentHashMap> cache) { // cleanup any dead entries if (rq.poll() != null) { - while (rq.poll() != null) - ; + while (rq.poll() != null); for (Map.Entry> e : cache.entrySet()) { Reference val = e.getValue(); if (val != null && val.get() == null) { @@ -69,7 +68,7 @@ private static long testString(int keyLen) { private static String getKey(int len) { StringBuilder sb = new StringBuilder(); - String[] chars = { "a", "b", "c", "d", "e", "f", "g", "h" }; + String[] chars = {"a", "b", "c", "d", "e", "f", "g", "h"}; int index = (int) Math.floor(Math.random() * 8); for (int i = 0; i < len; i++) { sb.append(chars[index]); @@ -82,7 +81,7 @@ public static void main(String[] args) { for (int i = 0; i < 10000; i++) { sum += testString(8); } - int[] keys = { 8, 64, 128 }; + int[] keys = {8, 64, 128}; for (int k : keys) { long start = System.currentTimeMillis(); diff --git a/src/main/java/net/rubyeye/xmemcached/utils/InetSocketAddressWrapper.java b/src/main/java/net/rubyeye/xmemcached/utils/InetSocketAddressWrapper.java index f2c331710..59b37bd45 100644 --- a/src/main/java/net/rubyeye/xmemcached/utils/InetSocketAddressWrapper.java +++ b/src/main/java/net/rubyeye/xmemcached/utils/InetSocketAddressWrapper.java @@ -48,7 +48,8 @@ public final InetSocketAddress getInetSocketAddress() { } } - public final void setInetSocketAddress(InetSocketAddress inetSocketAddress) { + public final void setInetSocketAddress( + InetSocketAddress inetSocketAddress) { this.inetSocketAddress = inetSocketAddress; if (inetSocketAddress != null) { this.hostName = inetSocketAddress.getHostName(); diff --git a/src/main/java/net/rubyeye/xmemcached/utils/XMemcachedClientFactoryBean.java b/src/main/java/net/rubyeye/xmemcached/utils/XMemcachedClientFactoryBean.java index 8070e2dc3..333282063 100644 --- a/src/main/java/net/rubyeye/xmemcached/utils/XMemcachedClientFactoryBean.java +++ b/src/main/java/net/rubyeye/xmemcached/utils/XMemcachedClientFactoryBean.java @@ -76,13 +76,13 @@ public class XMemcachedClientFactoryBean implements FactoryBean { private boolean failureMode; private long opTimeout = MemcachedClient.DEFAULT_OP_TIMEOUT; - + private long connectTimeout = MemcachedClient.DEFAULT_CONNECT_TIMEOUT; private KeyProvider keyProvider = DefaultKeyProvider.INSTANCE; private int maxQueuedNoReplyOperations = MemcachedClient.DEFAULT_MAX_QUEUED_NOPS; - + private long healSessionInterval = MemcachedClient.DEFAULT_HEAL_SESSION_INTERVAL; private boolean enableHealSession = true; diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/Main.java b/src/test/java/com/google/code/yanf4j/test/unittest/Main.java index ce7b31edb..eba1bb678 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/Main.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/Main.java @@ -4,13 +4,13 @@ public class Main { public static void main(String[] args) { long start = System.nanoTime(); int threadNum = 10000; - int sum=0; + int sum = 0; for (int i = 0; i < threadNum; i++) - sum+=testLock(i, i * 2); + sum += testLock(i, i * 2); System.out.println((System.nanoTime() - start) / threadNum); - System.out.println(sum); + System.out.println(sum); } - + public final static synchronized int testLock(int a, int b) { return a + b; } diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/buffer/Bar.java b/src/test/java/com/google/code/yanf4j/test/unittest/buffer/Bar.java index fb26e3ae7..a1eb932a5 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/buffer/Bar.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/buffer/Bar.java @@ -29,17 +29,15 @@ */ public class Bar extends Foo { - private static final long serialVersionUID = -7360624845308368521L; + private static final long serialVersionUID = -7360624845308368521L; - private int barValue; + private int barValue; + public int getBarValue() { + return barValue; + } - public int getBarValue() { - return barValue; - } - - - public void setBarValue(int barValue) { - this.barValue = barValue; - } + public void setBarValue(int barValue) { + this.barValue = barValue; + } } diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/buffer/Foo.java b/src/test/java/com/google/code/yanf4j/test/unittest/buffer/Foo.java index 994a0f6e0..f4eef76ff 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/buffer/Foo.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/buffer/Foo.java @@ -21,7 +21,6 @@ import java.io.Serializable; - /** * The parent class of {@link Bar}. It is used to test the serialization of * inherited object in {@link IoBufferTest}. @@ -32,17 +31,15 @@ */ public class Foo implements Serializable { - private static final long serialVersionUID = 6467037996528575216L; - - private int fooValue; - + private static final long serialVersionUID = 6467037996528575216L; - public int getFooValue() { - return fooValue; - } + private int fooValue; + public int getFooValue() { + return fooValue; + } - public void setFooValue(int fooValue) { - this.fooValue = fooValue; - } + public void setFooValue(int fooValue) { + this.fooValue = fooValue; + } } diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/buffer/IoBufferTest.java b/src/test/java/com/google/code/yanf4j/test/unittest/buffer/IoBufferTest.java index 1fb58f5a3..49ad3ba6f 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/buffer/IoBufferTest.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/buffer/IoBufferTest.java @@ -44,7 +44,6 @@ import static org.junit.Assert.fail; import com.google.code.yanf4j.buffer.IoBuffer; - /** * Tests {@link IoBuffer}. * @@ -54,1247 +53,1091 @@ */ public class IoBufferTest { - /* - * public static void main(String[] args) { - * junit.textui.TestRunner.run(IoBufferTest.class); } - */ - - @Before - public void setUp() throws Exception { - } - - - @After - public void tearDown() throws Exception { - } - - - @Test - public void testAllocate() throws Exception { - for (int i = 10; i < 1048576 * 2; i = i * 11 / 10) // increase by 10% - { - IoBuffer buf = IoBuffer.allocate(i); - assertEquals(0, buf.position()); - assertEquals(buf.capacity(), buf.remaining()); - assertTrue(buf.capacity() >= i); - assertTrue(buf.capacity() < i * 2); - } - } - - - @Test - public void testAutoExpand() throws Exception { - IoBuffer buf = IoBuffer.allocate(1); - - buf.put((byte) 0); - try { - buf.put((byte) 0); - fail("Buffer can't auto expand, with autoExpand property set at false"); - } - catch (BufferOverflowException e) { - // Expected Exception as auto expand property is false - assertTrue(true); - } - - buf.setAutoExpand(true); - buf.put((byte) 0); - assertEquals(2, buf.position()); - assertEquals(2, buf.limit()); - assertEquals(2, buf.capacity()); - - buf.setAutoExpand(false); - try { - buf.put(3, (byte) 0); - fail("Buffer can't auto expand, with autoExpand property set at false"); - } - catch (IndexOutOfBoundsException e) { - // Expected Exception as auto expand property is false - assertTrue(true); - } - - buf.setAutoExpand(true); - buf.put(3, (byte) 0); - assertEquals(2, buf.position()); - assertEquals(4, buf.limit()); - assertEquals(4, buf.capacity()); - - // Make sure the buffer is doubled up. - buf = IoBuffer.allocate(1).setAutoExpand(true); - int lastCapacity = buf.capacity(); - for (int i = 0; i < 1048576; i++) { - buf.put((byte) 0); - if (lastCapacity != buf.capacity()) { - assertEquals(lastCapacity * 2, buf.capacity()); - lastCapacity = buf.capacity(); - } - } - } - - - @Test - public void testAutoExpandMark() throws Exception { - IoBuffer buf = IoBuffer.allocate(4).setAutoExpand(true); - - buf.put((byte) 0); - buf.put((byte) 0); - buf.put((byte) 0); - - // Position should be 3 when we reset this buffer. - buf.mark(); - - // Overflow it - buf.put((byte) 0); - buf.put((byte) 0); - - assertEquals(5, buf.position()); - buf.reset(); - assertEquals(3, buf.position()); - } - - - @Test - public void testAutoShrink() throws Exception { - IoBuffer buf = IoBuffer.allocate(8).setAutoShrink(true); - - // Make sure the buffer doesn't shrink too much (less than the initial - // capacity.) - buf.sweep((byte) 1); - buf.fill(7); - buf.compact(); - assertEquals(8, buf.capacity()); - assertEquals(1, buf.position()); - assertEquals(8, buf.limit()); - buf.clear(); - assertEquals(1, buf.get()); - - // Expand the buffer. - buf.capacity(32).clear(); - assertEquals(32, buf.capacity()); - - // Make sure the buffer shrinks when only 1/4 is being used. - buf.sweep((byte) 1); - buf.fill(24); - buf.compact(); - assertEquals(16, buf.capacity()); - assertEquals(8, buf.position()); - assertEquals(16, buf.limit()); - buf.clear(); - for (int i = 0; i < 8; i++) { - assertEquals(1, buf.get()); - } - - // Expand the buffer. - buf.capacity(32).clear(); - assertEquals(32, buf.capacity()); - - // Make sure the buffer shrinks when only 1/8 is being used. - buf.sweep((byte) 1); - buf.fill(28); - buf.compact(); - assertEquals(8, buf.capacity()); - assertEquals(4, buf.position()); - assertEquals(8, buf.limit()); - buf.clear(); - for (int i = 0; i < 4; i++) { - assertEquals(1, buf.get()); - } - - // Expand the buffer. - buf.capacity(32).clear(); - assertEquals(32, buf.capacity()); - - // Make sure the buffer shrinks when 0 byte is being used. - buf.fill(32); - buf.compact(); - assertEquals(8, buf.capacity()); - assertEquals(0, buf.position()); - assertEquals(8, buf.limit()); - - // Expand the buffer. - buf.capacity(32).clear(); - assertEquals(32, buf.capacity()); - - // Make sure the buffer doesn't shrink when more than 1/4 is being used. - buf.sweep((byte) 1); - buf.fill(23); - buf.compact(); - assertEquals(32, buf.capacity()); - assertEquals(9, buf.position()); - assertEquals(32, buf.limit()); - buf.clear(); - for (int i = 0; i < 9; i++) { - assertEquals(1, buf.get()); - } - } - - - @Test - public void testGetString() throws Exception { - IoBuffer buf = IoBuffer.allocate(16); - CharsetDecoder decoder; - - Charset charset = Charset.forName("UTF-8"); - buf.clear(); - buf.putString("hello", charset.newEncoder()); - buf.put((byte) 0); - buf.flip(); - assertEquals("hello", buf.getString(charset.newDecoder())); - - buf.clear(); - buf.putString("hello", charset.newEncoder()); - buf.flip(); - assertEquals("hello", buf.getString(charset.newDecoder())); - - decoder = Charset.forName("ISO-8859-1").newDecoder(); - buf.clear(); - buf.put((byte) 'A'); - buf.put((byte) 'B'); - buf.put((byte) 'C'); - buf.put((byte) 0); - - buf.position(0); - assertEquals("ABC", buf.getString(decoder)); - assertEquals(4, buf.position()); - - buf.position(0); - buf.limit(1); - assertEquals("A", buf.getString(decoder)); - assertEquals(1, buf.position()); - - buf.clear(); - assertEquals("ABC", buf.getString(10, decoder)); - assertEquals(10, buf.position()); - - buf.clear(); - assertEquals("A", buf.getString(1, decoder)); - assertEquals(1, buf.position()); - - // Test a trailing garbage - buf.clear(); - buf.put((byte) 'A'); - buf.put((byte) 'B'); - buf.put((byte) 0); - buf.put((byte) 'C'); - buf.position(0); - assertEquals("AB", buf.getString(4, decoder)); - assertEquals(4, buf.position()); - - buf.clear(); - buf.fillAndReset(buf.limit()); - decoder = Charset.forName("UTF-16").newDecoder(); - buf.put((byte) 0); - buf.put((byte) 'A'); - buf.put((byte) 0); - buf.put((byte) 'B'); - buf.put((byte) 0); - buf.put((byte) 'C'); - buf.put((byte) 0); - buf.put((byte) 0); - - buf.position(0); - assertEquals("ABC", buf.getString(decoder)); - assertEquals(8, buf.position()); - - buf.position(0); - buf.limit(2); - assertEquals("A", buf.getString(decoder)); - assertEquals(2, buf.position()); - - buf.position(0); - buf.limit(3); - assertEquals("A", buf.getString(decoder)); - assertEquals(2, buf.position()); - - buf.clear(); - assertEquals("ABC", buf.getString(10, decoder)); - assertEquals(10, buf.position()); - - buf.clear(); - assertEquals("A", buf.getString(2, decoder)); - assertEquals(2, buf.position()); - - buf.clear(); - try { - buf.getString(1, decoder); - fail(); - } - catch (IllegalArgumentException e) { - // Expected an Exception, signifies test success - assertTrue(true); - } - - // Test getting strings from an empty buffer. - buf.clear(); - buf.limit(0); - assertEquals("", buf.getString(decoder)); - assertEquals("", buf.getString(2, decoder)); - - // Test getting strings from non-empty buffer which is filled with 0x00 - buf.clear(); - buf.putInt(0); - buf.clear(); - buf.limit(4); - assertEquals("", buf.getString(decoder)); - assertEquals(2, buf.position()); - assertEquals(4, buf.limit()); - - buf.position(0); - assertEquals("", buf.getString(2, decoder)); - assertEquals(2, buf.position()); - assertEquals(4, buf.limit()); - } - - - @Test - public void testGetStringWithFailure() throws Exception { - String test = "\u30b3\u30e1\u30f3\u30c8\u7de8\u96c6"; - IoBuffer buffer = IoBuffer.wrap(test.getBytes("Shift_JIS")); - - // Make sure the limit doesn't change when an exception arose. - int oldLimit = buffer.limit(); - int oldPos = buffer.position(); - try { - buffer.getString(3, Charset.forName("ASCII").newDecoder()); - fail(); - } - catch (Exception e) { - assertEquals(oldLimit, buffer.limit()); - assertEquals(oldPos, buffer.position()); - } - - try { - buffer.getString(Charset.forName("ASCII").newDecoder()); - fail(); - } - catch (Exception e) { - assertEquals(oldLimit, buffer.limit()); - assertEquals(oldPos, buffer.position()); - } - } - - - @Test - public void testPutString() throws Exception { - CharsetEncoder encoder; - IoBuffer buf = IoBuffer.allocate(16); - encoder = Charset.forName("ISO-8859-1").newEncoder(); - - buf.putString("ABC", encoder); - assertEquals(3, buf.position()); - buf.clear(); - assertEquals('A', buf.get(0)); - assertEquals('B', buf.get(1)); - assertEquals('C', buf.get(2)); - - buf.putString("D", 5, encoder); - assertEquals(5, buf.position()); - buf.clear(); - assertEquals('D', buf.get(0)); - assertEquals(0, buf.get(1)); - - buf.putString("EFG", 2, encoder); - assertEquals(2, buf.position()); - buf.clear(); - assertEquals('E', buf.get(0)); - assertEquals('F', buf.get(1)); - assertEquals('C', buf.get(2)); // C may not be overwritten - - // UTF-16: We specify byte order to omit BOM. - encoder = Charset.forName("UTF-16BE").newEncoder(); - buf.clear(); - - buf.putString("ABC", encoder); - assertEquals(6, buf.position()); - buf.clear(); - - assertEquals(0, buf.get(0)); - assertEquals('A', buf.get(1)); - assertEquals(0, buf.get(2)); - assertEquals('B', buf.get(3)); - assertEquals(0, buf.get(4)); - assertEquals('C', buf.get(5)); - - buf.putString("D", 10, encoder); - assertEquals(10, buf.position()); - buf.clear(); - assertEquals(0, buf.get(0)); - assertEquals('D', buf.get(1)); - assertEquals(0, buf.get(2)); - assertEquals(0, buf.get(3)); - - buf.putString("EFG", 4, encoder); - assertEquals(4, buf.position()); - buf.clear(); - assertEquals(0, buf.get(0)); - assertEquals('E', buf.get(1)); - assertEquals(0, buf.get(2)); - assertEquals('F', buf.get(3)); - assertEquals(0, buf.get(4)); // C may not be overwritten - assertEquals('C', buf.get(5)); // C may not be overwritten - - // Test putting an emptry string - buf.putString("", encoder); - assertEquals(0, buf.position()); - buf.putString("", 4, encoder); - assertEquals(4, buf.position()); - assertEquals(0, buf.get(0)); - assertEquals(0, buf.get(1)); - } - - - @Test - public void testGetPrefixedString() throws Exception { - IoBuffer buf = IoBuffer.allocate(16); - CharsetEncoder encoder; - CharsetDecoder decoder; - encoder = Charset.forName("ISO-8859-1").newEncoder(); - decoder = Charset.forName("ISO-8859-1").newDecoder(); - - buf.putShort((short) 3); - buf.putString("ABCD", encoder); - buf.clear(); - assertEquals("ABC", buf.getPrefixedString(decoder)); - } - - - @Test - public void testPutPrefixedString() throws Exception { - CharsetEncoder encoder; - IoBuffer buf = IoBuffer.allocate(16); - buf.fillAndReset(buf.remaining()); - encoder = Charset.forName("ISO-8859-1").newEncoder(); - - // Without autoExpand - buf.putPrefixedString("ABC", encoder); - assertEquals(5, buf.position()); - assertEquals(0, buf.get(0)); - assertEquals(3, buf.get(1)); - assertEquals('A', buf.get(2)); - assertEquals('B', buf.get(3)); - assertEquals('C', buf.get(4)); - - buf.clear(); - try { - buf.putPrefixedString("123456789012345", encoder); - fail(); - } - catch (BufferOverflowException e) { - // Expected an Exception, signifies test success - assertTrue(true); - } - - // With autoExpand - buf.clear(); - buf.setAutoExpand(true); - buf.putPrefixedString("123456789012345", encoder); - assertEquals(17, buf.position()); - assertEquals(0, buf.get(0)); - assertEquals(15, buf.get(1)); - assertEquals('1', buf.get(2)); - assertEquals('2', buf.get(3)); - assertEquals('3', buf.get(4)); - assertEquals('4', buf.get(5)); - assertEquals('5', buf.get(6)); - assertEquals('6', buf.get(7)); - assertEquals('7', buf.get(8)); - assertEquals('8', buf.get(9)); - assertEquals('9', buf.get(10)); - assertEquals('0', buf.get(11)); - assertEquals('1', buf.get(12)); - assertEquals('2', buf.get(13)); - assertEquals('3', buf.get(14)); - assertEquals('4', buf.get(15)); - assertEquals('5', buf.get(16)); - } - - - @Test - public void testPutPrefixedStringWithPrefixLength() throws Exception { - CharsetEncoder encoder = Charset.forName("ISO-8859-1").newEncoder(); - IoBuffer buf = IoBuffer.allocate(16).sweep().setAutoExpand(true); - - buf.putPrefixedString("A", 1, encoder); - assertEquals(2, buf.position()); - assertEquals(1, buf.get(0)); - assertEquals('A', buf.get(1)); - - buf.sweep(); - buf.putPrefixedString("A", 2, encoder); - assertEquals(3, buf.position()); - assertEquals(0, buf.get(0)); - assertEquals(1, buf.get(1)); - assertEquals('A', buf.get(2)); - - buf.sweep(); - buf.putPrefixedString("A", 4, encoder); - assertEquals(5, buf.position()); - assertEquals(0, buf.get(0)); - assertEquals(0, buf.get(1)); - assertEquals(0, buf.get(2)); - assertEquals(1, buf.get(3)); - assertEquals('A', buf.get(4)); - } - - - @Test - public void testPutPrefixedStringWithPadding() throws Exception { - CharsetEncoder encoder = Charset.forName("ISO-8859-1").newEncoder(); - IoBuffer buf = IoBuffer.allocate(16).sweep().setAutoExpand(true); - - buf.putPrefixedString("A", 1, 2, (byte) 32, encoder); - assertEquals(3, buf.position()); - assertEquals(2, buf.get(0)); - assertEquals('A', buf.get(1)); - assertEquals(' ', buf.get(2)); - - buf.sweep(); - buf.putPrefixedString("A", 1, 4, (byte) 32, encoder); - assertEquals(5, buf.position()); - assertEquals(4, buf.get(0)); - assertEquals('A', buf.get(1)); - assertEquals(' ', buf.get(2)); - assertEquals(' ', buf.get(3)); - assertEquals(' ', buf.get(4)); - } - - - @Test - public void testWideUtf8Characters() throws Exception { - Runnable r = new Runnable() { - public void run() { - IoBuffer buffer = IoBuffer.allocate(1); - buffer.setAutoExpand(true); - - Charset charset = Charset.forName("UTF-8"); - - CharsetEncoder encoder = charset.newEncoder(); - - for (int i = 0; i < 5; i++) { - try { - buffer.putString("\u89d2", encoder); - buffer.putPrefixedString("\u89d2", encoder); - } - catch (CharacterCodingException e) { - fail(e.getMessage()); - } - } - } - }; - - Thread t = new Thread(r); - t.setDaemon(true); - t.start(); - - for (int i = 0; i < 50; i++) { - Thread.sleep(100); - if (!t.isAlive()) { - break; - } - } - - if (t.isAlive()) { - t.interrupt(); - - fail("Went into endless loop trying to encode character"); - } - } - - - @Test - public void testObjectSerialization() throws Exception { - IoBuffer buf = IoBuffer.allocate(16); - buf.setAutoExpand(true); - List o = new ArrayList(); - o.add(new Date()); - o.add(long.class); - - // Test writing an object. - buf.putObject(o); - - // Test reading an object. - buf.clear(); - Object o2 = buf.getObject(); - assertEquals(o, o2); - - // This assertion is just to make sure that deserialization occurred. - assertNotSame(o, o2); - } - - - @Test - public void testInheritedObjectSerialization() throws Exception { - IoBuffer buf = IoBuffer.allocate(16); - buf.setAutoExpand(true); - - Bar expected = new Bar(); - expected.setFooValue(0x12345678); - expected.setBarValue(0x90ABCDEF); - - // Test writing an object. - buf.putObject(expected); - - // Test reading an object. - buf.clear(); - Bar actual = (Bar) buf.getObject(); - assertSame(Bar.class, actual.getClass()); - assertEquals(expected.getFooValue(), actual.getFooValue()); - assertEquals(expected.getBarValue(), actual.getBarValue()); - - // This assertion is just to make sure that deserialization occurred. - assertNotSame(expected, actual); - } - - - @Test - public void testSweepWithZeros() throws Exception { - IoBuffer buf = IoBuffer.allocate(4); - buf.putInt(0xdeadbeef); - buf.clear(); - assertEquals(0xdeadbeef, buf.getInt()); - assertEquals(4, buf.position()); - assertEquals(4, buf.limit()); - - buf.sweep(); - assertEquals(0, buf.position()); - assertEquals(4, buf.limit()); - assertEquals(0x0, buf.getInt()); - } - - - @Test - public void testSweepNonZeros() throws Exception { - IoBuffer buf = IoBuffer.allocate(4); - buf.putInt(0xdeadbeef); - buf.clear(); - assertEquals(0xdeadbeef, buf.getInt()); - assertEquals(4, buf.position()); - assertEquals(4, buf.limit()); - - buf.sweep((byte) 0x45); - assertEquals(0, buf.position()); - assertEquals(4, buf.limit()); - assertEquals(0x45454545, buf.getInt()); - } - - - @Test - public void testWrapNioBuffer() throws Exception { - ByteBuffer nioBuf = ByteBuffer.allocate(10); - nioBuf.position(3); - nioBuf.limit(7); - - IoBuffer buf = IoBuffer.wrap(nioBuf); - assertEquals(3, buf.position()); - assertEquals(7, buf.limit()); - assertEquals(10, buf.capacity()); - } - - - @Test - public void testWrapSubArray() throws Exception { - byte[] array = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; - - IoBuffer buf = IoBuffer.wrap(array, 3, 4); - assertEquals(3, buf.position()); - assertEquals(7, buf.limit()); - assertEquals(10, buf.capacity()); - - buf.clear(); - assertEquals(0, buf.position()); - assertEquals(10, buf.limit()); - assertEquals(10, buf.capacity()); - } - - - @Test - public void testDuplicate() throws Exception { - IoBuffer original; - IoBuffer duplicate; - - // Test if the buffer is duplicated correctly. - original = IoBuffer.allocate(16).sweep(); - original.position(4); - original.limit(10); - duplicate = original.duplicate(); - original.put(4, (byte) 127); - assertEquals(4, duplicate.position()); - assertEquals(10, duplicate.limit()); - assertEquals(16, duplicate.capacity()); - assertNotSame(original.buf(), duplicate.buf()); - assertSame(original.buf().array(), duplicate.buf().array()); - assertEquals(127, duplicate.get(4)); - - // Test a duplicate of a duplicate. - original = IoBuffer.allocate(16); - duplicate = original.duplicate().duplicate(); - assertNotSame(original.buf(), duplicate.buf()); - assertSame(original.buf().array(), duplicate.buf().array()); - - // Try to expand. - original = IoBuffer.allocate(16); - original.setAutoExpand(true); - duplicate = original.duplicate(); - assertFalse(original.isAutoExpand()); - - try { - original.setAutoExpand(true); - fail("Derived buffers and their parent can't be expanded"); - } - catch (IllegalStateException e) { - // Expected an Exception, signifies test success - assertTrue(true); - } - - try { - duplicate.setAutoExpand(true); - fail("Derived buffers and their parent can't be expanded"); - } - catch (IllegalStateException e) { - // Expected an Exception, signifies test success - assertTrue(true); - } - } - - - @Test - public void testSlice() throws Exception { - IoBuffer original; - IoBuffer slice; - - // Test if the buffer is sliced correctly. - original = IoBuffer.allocate(16).sweep(); - original.position(4); - original.limit(10); - slice = original.slice(); - original.put(4, (byte) 127); - assertEquals(0, slice.position()); - assertEquals(6, slice.limit()); - assertEquals(6, slice.capacity()); - assertNotSame(original.buf(), slice.buf()); - assertEquals(127, slice.get(0)); - } - - - @Test - public void testReadOnlyBuffer() throws Exception { - IoBuffer original; - IoBuffer duplicate; - - // Test if the buffer is duplicated correctly. - original = IoBuffer.allocate(16).sweep(); - original.position(4); - original.limit(10); - duplicate = original.asReadOnlyBuffer(); - original.put(4, (byte) 127); - assertEquals(4, duplicate.position()); - assertEquals(10, duplicate.limit()); - assertEquals(16, duplicate.capacity()); - assertNotSame(original.buf(), duplicate.buf()); - assertEquals(127, duplicate.get(4)); - - // Try to expand. - try { - original = IoBuffer.allocate(16); - duplicate = original.asReadOnlyBuffer(); - duplicate.putString("A very very very very looooooong string", Charset.forName("ISO-8859-1").newEncoder()); - fail("ReadOnly buffer's can't be expanded"); - } - catch (ReadOnlyBufferException e) { - // Expected an Exception, signifies test success - assertTrue(true); - } - } - - - @Test - public void testGetUnsigned() throws Exception { - IoBuffer buf = IoBuffer.allocate(16); - buf.put((byte) 0xA4); - buf.put((byte) 0xD0); - buf.put((byte) 0xB3); - buf.put((byte) 0xCD); - buf.flip(); - - buf.order(ByteOrder.LITTLE_ENDIAN); - - buf.mark(); - assertEquals(0xA4, buf.getUnsigned()); - buf.reset(); - assertEquals(0xD0A4, buf.getUnsignedShort()); - buf.reset(); - assertEquals(0xCDB3D0A4L, buf.getUnsignedInt()); - } - - - @Test - public void testIndexOf() throws Exception { - boolean direct = false; - for (int i = 0; i < 2; i++, direct = !direct) { - IoBuffer buf = IoBuffer.allocate(16, direct); - buf.put((byte) 0x1); - buf.put((byte) 0x2); - buf.put((byte) 0x3); - buf.put((byte) 0x4); - buf.put((byte) 0x1); - buf.put((byte) 0x2); - buf.put((byte) 0x3); - buf.put((byte) 0x4); - buf.position(2); - buf.limit(5); - - assertEquals(4, buf.indexOf((byte) 0x1)); - assertEquals(-1, buf.indexOf((byte) 0x2)); - assertEquals(2, buf.indexOf((byte) 0x3)); - assertEquals(3, buf.indexOf((byte) 0x4)); - } - } - - // We need an enum with 64 values - private static enum TestEnum { - E1, - E2, - E3, - E4, - E5, - E6, - E7, - E8, - E9, - E10, - E11, - E12, - E13, - E14, - E15, - E16, - E17, - E18, - E19, - E20, - E21, - E22, - E23, - E24, - E25, - E26, - E27, - E28, - E29, - E30, - E31, - E32, - E33, - E34, - E35, - E36, - E37, - E38, - E39, - E40, - E41, - E42, - E43, - E44, - E45, - E46, - E77, - E48, - E49, - E50, - E51, - E52, - E53, - E54, - E55, - E56, - E57, - E58, - E59, - E60, - E61, - E62, - E63, - E64 - } - - private static enum TooBigEnum { - E1, - E2, - E3, - E4, - E5, - E6, - E7, - E8, - E9, - E10, - E11, - E12, - E13, - E14, - E15, - E16, - E17, - E18, - E19, - E20, - E21, - E22, - E23, - E24, - E25, - E26, - E27, - E28, - E29, - E30, - E31, - E32, - E33, - E34, - E35, - E36, - E37, - E38, - E39, - E40, - E41, - E42, - E43, - E44, - E45, - E46, - E77, - E48, - E49, - E50, - E51, - E52, - E53, - E54, - E55, - E56, - E57, - E58, - E59, - E60, - E61, - E62, - E63, - E64, - E65 - } - - - @Test - public void testPutEnumSet() { - IoBuffer buf = IoBuffer.allocate(8); - - // Test empty set - buf.putEnumSet(EnumSet.noneOf(TestEnum.class)); - buf.flip(); - assertEquals(0, buf.get()); - - buf.clear(); - buf.putEnumSetShort(EnumSet.noneOf(TestEnum.class)); - buf.flip(); - assertEquals(0, buf.getShort()); - - buf.clear(); - buf.putEnumSetInt(EnumSet.noneOf(TestEnum.class)); - buf.flip(); - assertEquals(0, buf.getInt()); - - buf.clear(); - buf.putEnumSetLong(EnumSet.noneOf(TestEnum.class)); - buf.flip(); - assertEquals(0, buf.getLong()); - - // Test complete set - buf.clear(); - buf.putEnumSet(EnumSet.range(TestEnum.E1, TestEnum.E8)); - buf.flip(); - assertEquals((byte) -1, buf.get()); - - buf.clear(); - buf.putEnumSetShort(EnumSet.range(TestEnum.E1, TestEnum.E16)); - buf.flip(); - assertEquals((short) -1, buf.getShort()); - - buf.clear(); - buf.putEnumSetInt(EnumSet.range(TestEnum.E1, TestEnum.E32)); - buf.flip(); - assertEquals(-1, buf.getInt()); - - buf.clear(); - buf.putEnumSetLong(EnumSet.allOf(TestEnum.class)); - buf.flip(); - assertEquals(-1L, buf.getLong()); - - // Test high bit set - buf.clear(); - buf.putEnumSet(EnumSet.of(TestEnum.E8)); - buf.flip(); - assertEquals(Byte.MIN_VALUE, buf.get()); - - buf.clear(); - buf.putEnumSetShort(EnumSet.of(TestEnum.E16)); - buf.flip(); - assertEquals(Short.MIN_VALUE, buf.getShort()); - - buf.clear(); - buf.putEnumSetInt(EnumSet.of(TestEnum.E32)); - buf.flip(); - assertEquals(Integer.MIN_VALUE, buf.getInt()); - - buf.clear(); - buf.putEnumSetLong(EnumSet.of(TestEnum.E64)); - buf.flip(); - assertEquals(Long.MIN_VALUE, buf.getLong()); - - // Test high low bits set - buf.clear(); - buf.putEnumSet(EnumSet.of(TestEnum.E1, TestEnum.E8)); - buf.flip(); - assertEquals(Byte.MIN_VALUE + 1, buf.get()); - - buf.clear(); - buf.putEnumSetShort(EnumSet.of(TestEnum.E1, TestEnum.E16)); - buf.flip(); - assertEquals(Short.MIN_VALUE + 1, buf.getShort()); - - buf.clear(); - buf.putEnumSetInt(EnumSet.of(TestEnum.E1, TestEnum.E32)); - buf.flip(); - assertEquals(Integer.MIN_VALUE + 1, buf.getInt()); - - buf.clear(); - buf.putEnumSetLong(EnumSet.of(TestEnum.E1, TestEnum.E64)); - buf.flip(); - assertEquals(Long.MIN_VALUE + 1, buf.getLong()); - } - - - @Test - public void testGetEnumSet() { - IoBuffer buf = IoBuffer.allocate(8); - - // Test empty set - buf.put((byte) 0); - buf.flip(); - assertEquals(EnumSet.noneOf(TestEnum.class), buf.getEnumSet(TestEnum.class)); - - buf.clear(); - buf.putShort((short) 0); - buf.flip(); - assertEquals(EnumSet.noneOf(TestEnum.class), buf.getEnumSet(TestEnum.class)); - - buf.clear(); - buf.putInt(0); - buf.flip(); - assertEquals(EnumSet.noneOf(TestEnum.class), buf.getEnumSet(TestEnum.class)); - - buf.clear(); - buf.putLong(0L); - buf.flip(); - assertEquals(EnumSet.noneOf(TestEnum.class), buf.getEnumSet(TestEnum.class)); - - // Test complete set - buf.clear(); - buf.put((byte) -1); - buf.flip(); - assertEquals(EnumSet.range(TestEnum.E1, TestEnum.E8), buf.getEnumSet(TestEnum.class)); - - buf.clear(); - buf.putShort((short) -1); - buf.flip(); - assertEquals(EnumSet.range(TestEnum.E1, TestEnum.E16), buf.getEnumSetShort(TestEnum.class)); - - buf.clear(); - buf.putInt(-1); - buf.flip(); - assertEquals(EnumSet.range(TestEnum.E1, TestEnum.E32), buf.getEnumSetInt(TestEnum.class)); - - buf.clear(); - buf.putLong(-1L); - buf.flip(); - assertEquals(EnumSet.allOf(TestEnum.class), buf.getEnumSetLong(TestEnum.class)); - - // Test high bit set - buf.clear(); - buf.put(Byte.MIN_VALUE); - buf.flip(); - assertEquals(EnumSet.of(TestEnum.E8), buf.getEnumSet(TestEnum.class)); - - buf.clear(); - buf.putShort(Short.MIN_VALUE); - buf.flip(); - assertEquals(EnumSet.of(TestEnum.E16), buf.getEnumSetShort(TestEnum.class)); - - buf.clear(); - buf.putInt(Integer.MIN_VALUE); - buf.flip(); - assertEquals(EnumSet.of(TestEnum.E32), buf.getEnumSetInt(TestEnum.class)); - - buf.clear(); - buf.putLong(Long.MIN_VALUE); - buf.flip(); - assertEquals(EnumSet.of(TestEnum.E64), buf.getEnumSetLong(TestEnum.class)); - - // Test high low bits set - buf.clear(); - byte b = Byte.MIN_VALUE + 1; - buf.put(b); - buf.flip(); - assertEquals(EnumSet.of(TestEnum.E1, TestEnum.E8), buf.getEnumSet(TestEnum.class)); - - buf.clear(); - short s = Short.MIN_VALUE + 1; - buf.putShort(s); - buf.flip(); - assertEquals(EnumSet.of(TestEnum.E1, TestEnum.E16), buf.getEnumSetShort(TestEnum.class)); - - buf.clear(); - buf.putInt(Integer.MIN_VALUE + 1); - buf.flip(); - assertEquals(EnumSet.of(TestEnum.E1, TestEnum.E32), buf.getEnumSetInt(TestEnum.class)); - - buf.clear(); - buf.putLong(Long.MIN_VALUE + 1); - buf.flip(); - assertEquals(EnumSet.of(TestEnum.E1, TestEnum.E64), buf.getEnumSetLong(TestEnum.class)); - } - - - @Test - public void testBitVectorOverFlow() { - IoBuffer buf = IoBuffer.allocate(8); - try { - buf.putEnumSet(EnumSet.of(TestEnum.E9)); - fail("Should have thrown IllegalArgumentException"); - } - catch (IllegalArgumentException e) { - // Expected an Exception, signifies test success - assertTrue(true); - } - - try { - buf.putEnumSetShort(EnumSet.of(TestEnum.E17)); - fail("Should have thrown IllegalArgumentException"); - } - catch (IllegalArgumentException e) { - // Expected an Exception, signifies test success - assertTrue(true); - } - - try { - buf.putEnumSetInt(EnumSet.of(TestEnum.E33)); - fail("Should have thrown IllegalArgumentException"); - } - catch (IllegalArgumentException e) { - // Expected an Exception, signifies test success - assertTrue(true); - } - - try { - buf.putEnumSetLong(EnumSet.of(TooBigEnum.E65)); - fail("Should have thrown IllegalArgumentException"); - } - catch (IllegalArgumentException e) { - // Expected an Exception, signifies test success - assertTrue(true); - } - } - - - @Test - public void testGetPutEnum() { - IoBuffer buf = IoBuffer.allocate(4); - - buf.putEnum(TestEnum.E64); - buf.flip(); - assertEquals(TestEnum.E64, buf.getEnum(TestEnum.class)); - - buf.clear(); - buf.putEnumShort(TestEnum.E64); - buf.flip(); - assertEquals(TestEnum.E64, buf.getEnumShort(TestEnum.class)); - - buf.clear(); - buf.putEnumInt(TestEnum.E64); - buf.flip(); - assertEquals(TestEnum.E64, buf.getEnumInt(TestEnum.class)); - } - - - @Test - public void testGetMediumInt() { - IoBuffer buf = IoBuffer.allocate(3); - - buf.put((byte) 0x01); - buf.put((byte) 0x02); - buf.put((byte) 0x03); - assertEquals(3, buf.position()); - - buf.flip(); - assertEquals(0x010203, buf.getMediumInt()); - assertEquals(0x010203, buf.getMediumInt(0)); - buf.flip(); - assertEquals(0x010203, buf.getUnsignedMediumInt()); - assertEquals(0x010203, buf.getUnsignedMediumInt(0)); - buf.flip(); - assertEquals(0x010203, buf.getUnsignedMediumInt()); - buf.flip().order(ByteOrder.LITTLE_ENDIAN); - assertEquals(0x030201, buf.getMediumInt()); - assertEquals(0x030201, buf.getMediumInt(0)); - - // Test max medium int - buf.flip().order(ByteOrder.BIG_ENDIAN); - buf.put((byte) 0x7f); - buf.put((byte) 0xff); - buf.put((byte) 0xff); - buf.flip(); - assertEquals(0x7fffff, buf.getMediumInt()); - assertEquals(0x7fffff, buf.getMediumInt(0)); - - // Test negative number - buf.flip().order(ByteOrder.BIG_ENDIAN); - buf.put((byte) 0xff); - buf.put((byte) 0x02); - buf.put((byte) 0x03); - buf.flip(); - - assertEquals(0xffff0203, buf.getMediumInt()); - assertEquals(0xffff0203, buf.getMediumInt(0)); - buf.flip(); - - assertEquals(0x00ff0203, buf.getUnsignedMediumInt()); - assertEquals(0x00ff0203, buf.getUnsignedMediumInt(0)); - } - - - @Test - public void testPutMediumInt() { - IoBuffer buf = IoBuffer.allocate(3); - - checkMediumInt(buf, 0); - checkMediumInt(buf, 1); - checkMediumInt(buf, -1); - checkMediumInt(buf, 0x7fffff); - } - - - private void checkMediumInt(IoBuffer buf, int x) { - buf.putMediumInt(x); - assertEquals(3, buf.position()); - buf.flip(); - assertEquals(x, buf.getMediumInt()); - assertEquals(3, buf.position()); - - buf.putMediumInt(0, x); - assertEquals(3, buf.position()); - assertEquals(x, buf.getMediumInt(0)); - - buf.flip(); - } + /* + * public static void main(String[] args) { + * junit.textui.TestRunner.run(IoBufferTest.class); } + */ + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testAllocate() throws Exception { + for (int i = 10; i < 1048576 * 2; i = i * 11 / 10) // increase by 10% + { + IoBuffer buf = IoBuffer.allocate(i); + assertEquals(0, buf.position()); + assertEquals(buf.capacity(), buf.remaining()); + assertTrue(buf.capacity() >= i); + assertTrue(buf.capacity() < i * 2); + } + } + + @Test + public void testAutoExpand() throws Exception { + IoBuffer buf = IoBuffer.allocate(1); + + buf.put((byte) 0); + try { + buf.put((byte) 0); + fail("Buffer can't auto expand, with autoExpand property set at false"); + } catch (BufferOverflowException e) { + // Expected Exception as auto expand property is false + assertTrue(true); + } + + buf.setAutoExpand(true); + buf.put((byte) 0); + assertEquals(2, buf.position()); + assertEquals(2, buf.limit()); + assertEquals(2, buf.capacity()); + + buf.setAutoExpand(false); + try { + buf.put(3, (byte) 0); + fail("Buffer can't auto expand, with autoExpand property set at false"); + } catch (IndexOutOfBoundsException e) { + // Expected Exception as auto expand property is false + assertTrue(true); + } + + buf.setAutoExpand(true); + buf.put(3, (byte) 0); + assertEquals(2, buf.position()); + assertEquals(4, buf.limit()); + assertEquals(4, buf.capacity()); + + // Make sure the buffer is doubled up. + buf = IoBuffer.allocate(1).setAutoExpand(true); + int lastCapacity = buf.capacity(); + for (int i = 0; i < 1048576; i++) { + buf.put((byte) 0); + if (lastCapacity != buf.capacity()) { + assertEquals(lastCapacity * 2, buf.capacity()); + lastCapacity = buf.capacity(); + } + } + } + + @Test + public void testAutoExpandMark() throws Exception { + IoBuffer buf = IoBuffer.allocate(4).setAutoExpand(true); + + buf.put((byte) 0); + buf.put((byte) 0); + buf.put((byte) 0); + + // Position should be 3 when we reset this buffer. + buf.mark(); + + // Overflow it + buf.put((byte) 0); + buf.put((byte) 0); + + assertEquals(5, buf.position()); + buf.reset(); + assertEquals(3, buf.position()); + } + + @Test + public void testAutoShrink() throws Exception { + IoBuffer buf = IoBuffer.allocate(8).setAutoShrink(true); + + // Make sure the buffer doesn't shrink too much (less than the initial + // capacity.) + buf.sweep((byte) 1); + buf.fill(7); + buf.compact(); + assertEquals(8, buf.capacity()); + assertEquals(1, buf.position()); + assertEquals(8, buf.limit()); + buf.clear(); + assertEquals(1, buf.get()); + + // Expand the buffer. + buf.capacity(32).clear(); + assertEquals(32, buf.capacity()); + + // Make sure the buffer shrinks when only 1/4 is being used. + buf.sweep((byte) 1); + buf.fill(24); + buf.compact(); + assertEquals(16, buf.capacity()); + assertEquals(8, buf.position()); + assertEquals(16, buf.limit()); + buf.clear(); + for (int i = 0; i < 8; i++) { + assertEquals(1, buf.get()); + } + + // Expand the buffer. + buf.capacity(32).clear(); + assertEquals(32, buf.capacity()); + + // Make sure the buffer shrinks when only 1/8 is being used. + buf.sweep((byte) 1); + buf.fill(28); + buf.compact(); + assertEquals(8, buf.capacity()); + assertEquals(4, buf.position()); + assertEquals(8, buf.limit()); + buf.clear(); + for (int i = 0; i < 4; i++) { + assertEquals(1, buf.get()); + } + + // Expand the buffer. + buf.capacity(32).clear(); + assertEquals(32, buf.capacity()); + + // Make sure the buffer shrinks when 0 byte is being used. + buf.fill(32); + buf.compact(); + assertEquals(8, buf.capacity()); + assertEquals(0, buf.position()); + assertEquals(8, buf.limit()); + + // Expand the buffer. + buf.capacity(32).clear(); + assertEquals(32, buf.capacity()); + + // Make sure the buffer doesn't shrink when more than 1/4 is being used. + buf.sweep((byte) 1); + buf.fill(23); + buf.compact(); + assertEquals(32, buf.capacity()); + assertEquals(9, buf.position()); + assertEquals(32, buf.limit()); + buf.clear(); + for (int i = 0; i < 9; i++) { + assertEquals(1, buf.get()); + } + } + + @Test + public void testGetString() throws Exception { + IoBuffer buf = IoBuffer.allocate(16); + CharsetDecoder decoder; + + Charset charset = Charset.forName("UTF-8"); + buf.clear(); + buf.putString("hello", charset.newEncoder()); + buf.put((byte) 0); + buf.flip(); + assertEquals("hello", buf.getString(charset.newDecoder())); + + buf.clear(); + buf.putString("hello", charset.newEncoder()); + buf.flip(); + assertEquals("hello", buf.getString(charset.newDecoder())); + + decoder = Charset.forName("ISO-8859-1").newDecoder(); + buf.clear(); + buf.put((byte) 'A'); + buf.put((byte) 'B'); + buf.put((byte) 'C'); + buf.put((byte) 0); + + buf.position(0); + assertEquals("ABC", buf.getString(decoder)); + assertEquals(4, buf.position()); + + buf.position(0); + buf.limit(1); + assertEquals("A", buf.getString(decoder)); + assertEquals(1, buf.position()); + + buf.clear(); + assertEquals("ABC", buf.getString(10, decoder)); + assertEquals(10, buf.position()); + + buf.clear(); + assertEquals("A", buf.getString(1, decoder)); + assertEquals(1, buf.position()); + + // Test a trailing garbage + buf.clear(); + buf.put((byte) 'A'); + buf.put((byte) 'B'); + buf.put((byte) 0); + buf.put((byte) 'C'); + buf.position(0); + assertEquals("AB", buf.getString(4, decoder)); + assertEquals(4, buf.position()); + + buf.clear(); + buf.fillAndReset(buf.limit()); + decoder = Charset.forName("UTF-16").newDecoder(); + buf.put((byte) 0); + buf.put((byte) 'A'); + buf.put((byte) 0); + buf.put((byte) 'B'); + buf.put((byte) 0); + buf.put((byte) 'C'); + buf.put((byte) 0); + buf.put((byte) 0); + + buf.position(0); + assertEquals("ABC", buf.getString(decoder)); + assertEquals(8, buf.position()); + + buf.position(0); + buf.limit(2); + assertEquals("A", buf.getString(decoder)); + assertEquals(2, buf.position()); + + buf.position(0); + buf.limit(3); + assertEquals("A", buf.getString(decoder)); + assertEquals(2, buf.position()); + + buf.clear(); + assertEquals("ABC", buf.getString(10, decoder)); + assertEquals(10, buf.position()); + + buf.clear(); + assertEquals("A", buf.getString(2, decoder)); + assertEquals(2, buf.position()); + + buf.clear(); + try { + buf.getString(1, decoder); + fail(); + } catch (IllegalArgumentException e) { + // Expected an Exception, signifies test success + assertTrue(true); + } + + // Test getting strings from an empty buffer. + buf.clear(); + buf.limit(0); + assertEquals("", buf.getString(decoder)); + assertEquals("", buf.getString(2, decoder)); + + // Test getting strings from non-empty buffer which is filled with 0x00 + buf.clear(); + buf.putInt(0); + buf.clear(); + buf.limit(4); + assertEquals("", buf.getString(decoder)); + assertEquals(2, buf.position()); + assertEquals(4, buf.limit()); + + buf.position(0); + assertEquals("", buf.getString(2, decoder)); + assertEquals(2, buf.position()); + assertEquals(4, buf.limit()); + } + + @Test + public void testGetStringWithFailure() throws Exception { + String test = "\u30b3\u30e1\u30f3\u30c8\u7de8\u96c6"; + IoBuffer buffer = IoBuffer.wrap(test.getBytes("Shift_JIS")); + + // Make sure the limit doesn't change when an exception arose. + int oldLimit = buffer.limit(); + int oldPos = buffer.position(); + try { + buffer.getString(3, Charset.forName("ASCII").newDecoder()); + fail(); + } catch (Exception e) { + assertEquals(oldLimit, buffer.limit()); + assertEquals(oldPos, buffer.position()); + } + + try { + buffer.getString(Charset.forName("ASCII").newDecoder()); + fail(); + } catch (Exception e) { + assertEquals(oldLimit, buffer.limit()); + assertEquals(oldPos, buffer.position()); + } + } + + @Test + public void testPutString() throws Exception { + CharsetEncoder encoder; + IoBuffer buf = IoBuffer.allocate(16); + encoder = Charset.forName("ISO-8859-1").newEncoder(); + + buf.putString("ABC", encoder); + assertEquals(3, buf.position()); + buf.clear(); + assertEquals('A', buf.get(0)); + assertEquals('B', buf.get(1)); + assertEquals('C', buf.get(2)); + + buf.putString("D", 5, encoder); + assertEquals(5, buf.position()); + buf.clear(); + assertEquals('D', buf.get(0)); + assertEquals(0, buf.get(1)); + + buf.putString("EFG", 2, encoder); + assertEquals(2, buf.position()); + buf.clear(); + assertEquals('E', buf.get(0)); + assertEquals('F', buf.get(1)); + assertEquals('C', buf.get(2)); // C may not be overwritten + + // UTF-16: We specify byte order to omit BOM. + encoder = Charset.forName("UTF-16BE").newEncoder(); + buf.clear(); + + buf.putString("ABC", encoder); + assertEquals(6, buf.position()); + buf.clear(); + + assertEquals(0, buf.get(0)); + assertEquals('A', buf.get(1)); + assertEquals(0, buf.get(2)); + assertEquals('B', buf.get(3)); + assertEquals(0, buf.get(4)); + assertEquals('C', buf.get(5)); + + buf.putString("D", 10, encoder); + assertEquals(10, buf.position()); + buf.clear(); + assertEquals(0, buf.get(0)); + assertEquals('D', buf.get(1)); + assertEquals(0, buf.get(2)); + assertEquals(0, buf.get(3)); + + buf.putString("EFG", 4, encoder); + assertEquals(4, buf.position()); + buf.clear(); + assertEquals(0, buf.get(0)); + assertEquals('E', buf.get(1)); + assertEquals(0, buf.get(2)); + assertEquals('F', buf.get(3)); + assertEquals(0, buf.get(4)); // C may not be overwritten + assertEquals('C', buf.get(5)); // C may not be overwritten + + // Test putting an emptry string + buf.putString("", encoder); + assertEquals(0, buf.position()); + buf.putString("", 4, encoder); + assertEquals(4, buf.position()); + assertEquals(0, buf.get(0)); + assertEquals(0, buf.get(1)); + } + + @Test + public void testGetPrefixedString() throws Exception { + IoBuffer buf = IoBuffer.allocate(16); + CharsetEncoder encoder; + CharsetDecoder decoder; + encoder = Charset.forName("ISO-8859-1").newEncoder(); + decoder = Charset.forName("ISO-8859-1").newDecoder(); + + buf.putShort((short) 3); + buf.putString("ABCD", encoder); + buf.clear(); + assertEquals("ABC", buf.getPrefixedString(decoder)); + } + + @Test + public void testPutPrefixedString() throws Exception { + CharsetEncoder encoder; + IoBuffer buf = IoBuffer.allocate(16); + buf.fillAndReset(buf.remaining()); + encoder = Charset.forName("ISO-8859-1").newEncoder(); + + // Without autoExpand + buf.putPrefixedString("ABC", encoder); + assertEquals(5, buf.position()); + assertEquals(0, buf.get(0)); + assertEquals(3, buf.get(1)); + assertEquals('A', buf.get(2)); + assertEquals('B', buf.get(3)); + assertEquals('C', buf.get(4)); + + buf.clear(); + try { + buf.putPrefixedString("123456789012345", encoder); + fail(); + } catch (BufferOverflowException e) { + // Expected an Exception, signifies test success + assertTrue(true); + } + + // With autoExpand + buf.clear(); + buf.setAutoExpand(true); + buf.putPrefixedString("123456789012345", encoder); + assertEquals(17, buf.position()); + assertEquals(0, buf.get(0)); + assertEquals(15, buf.get(1)); + assertEquals('1', buf.get(2)); + assertEquals('2', buf.get(3)); + assertEquals('3', buf.get(4)); + assertEquals('4', buf.get(5)); + assertEquals('5', buf.get(6)); + assertEquals('6', buf.get(7)); + assertEquals('7', buf.get(8)); + assertEquals('8', buf.get(9)); + assertEquals('9', buf.get(10)); + assertEquals('0', buf.get(11)); + assertEquals('1', buf.get(12)); + assertEquals('2', buf.get(13)); + assertEquals('3', buf.get(14)); + assertEquals('4', buf.get(15)); + assertEquals('5', buf.get(16)); + } + + @Test + public void testPutPrefixedStringWithPrefixLength() throws Exception { + CharsetEncoder encoder = Charset.forName("ISO-8859-1").newEncoder(); + IoBuffer buf = IoBuffer.allocate(16).sweep().setAutoExpand(true); + + buf.putPrefixedString("A", 1, encoder); + assertEquals(2, buf.position()); + assertEquals(1, buf.get(0)); + assertEquals('A', buf.get(1)); + + buf.sweep(); + buf.putPrefixedString("A", 2, encoder); + assertEquals(3, buf.position()); + assertEquals(0, buf.get(0)); + assertEquals(1, buf.get(1)); + assertEquals('A', buf.get(2)); + + buf.sweep(); + buf.putPrefixedString("A", 4, encoder); + assertEquals(5, buf.position()); + assertEquals(0, buf.get(0)); + assertEquals(0, buf.get(1)); + assertEquals(0, buf.get(2)); + assertEquals(1, buf.get(3)); + assertEquals('A', buf.get(4)); + } + + @Test + public void testPutPrefixedStringWithPadding() throws Exception { + CharsetEncoder encoder = Charset.forName("ISO-8859-1").newEncoder(); + IoBuffer buf = IoBuffer.allocate(16).sweep().setAutoExpand(true); + + buf.putPrefixedString("A", 1, 2, (byte) 32, encoder); + assertEquals(3, buf.position()); + assertEquals(2, buf.get(0)); + assertEquals('A', buf.get(1)); + assertEquals(' ', buf.get(2)); + + buf.sweep(); + buf.putPrefixedString("A", 1, 4, (byte) 32, encoder); + assertEquals(5, buf.position()); + assertEquals(4, buf.get(0)); + assertEquals('A', buf.get(1)); + assertEquals(' ', buf.get(2)); + assertEquals(' ', buf.get(3)); + assertEquals(' ', buf.get(4)); + } + + @Test + public void testWideUtf8Characters() throws Exception { + Runnable r = new Runnable() { + public void run() { + IoBuffer buffer = IoBuffer.allocate(1); + buffer.setAutoExpand(true); + + Charset charset = Charset.forName("UTF-8"); + + CharsetEncoder encoder = charset.newEncoder(); + + for (int i = 0; i < 5; i++) { + try { + buffer.putString("\u89d2", encoder); + buffer.putPrefixedString("\u89d2", encoder); + } catch (CharacterCodingException e) { + fail(e.getMessage()); + } + } + } + }; + + Thread t = new Thread(r); + t.setDaemon(true); + t.start(); + + for (int i = 0; i < 50; i++) { + Thread.sleep(100); + if (!t.isAlive()) { + break; + } + } + + if (t.isAlive()) { + t.interrupt(); + + fail("Went into endless loop trying to encode character"); + } + } + + @Test + public void testObjectSerialization() throws Exception { + IoBuffer buf = IoBuffer.allocate(16); + buf.setAutoExpand(true); + List o = new ArrayList(); + o.add(new Date()); + o.add(long.class); + + // Test writing an object. + buf.putObject(o); + + // Test reading an object. + buf.clear(); + Object o2 = buf.getObject(); + assertEquals(o, o2); + + // This assertion is just to make sure that deserialization occurred. + assertNotSame(o, o2); + } + + @Test + public void testInheritedObjectSerialization() throws Exception { + IoBuffer buf = IoBuffer.allocate(16); + buf.setAutoExpand(true); + + Bar expected = new Bar(); + expected.setFooValue(0x12345678); + expected.setBarValue(0x90ABCDEF); + + // Test writing an object. + buf.putObject(expected); + + // Test reading an object. + buf.clear(); + Bar actual = (Bar) buf.getObject(); + assertSame(Bar.class, actual.getClass()); + assertEquals(expected.getFooValue(), actual.getFooValue()); + assertEquals(expected.getBarValue(), actual.getBarValue()); + + // This assertion is just to make sure that deserialization occurred. + assertNotSame(expected, actual); + } + + @Test + public void testSweepWithZeros() throws Exception { + IoBuffer buf = IoBuffer.allocate(4); + buf.putInt(0xdeadbeef); + buf.clear(); + assertEquals(0xdeadbeef, buf.getInt()); + assertEquals(4, buf.position()); + assertEquals(4, buf.limit()); + + buf.sweep(); + assertEquals(0, buf.position()); + assertEquals(4, buf.limit()); + assertEquals(0x0, buf.getInt()); + } + + @Test + public void testSweepNonZeros() throws Exception { + IoBuffer buf = IoBuffer.allocate(4); + buf.putInt(0xdeadbeef); + buf.clear(); + assertEquals(0xdeadbeef, buf.getInt()); + assertEquals(4, buf.position()); + assertEquals(4, buf.limit()); + + buf.sweep((byte) 0x45); + assertEquals(0, buf.position()); + assertEquals(4, buf.limit()); + assertEquals(0x45454545, buf.getInt()); + } + + @Test + public void testWrapNioBuffer() throws Exception { + ByteBuffer nioBuf = ByteBuffer.allocate(10); + nioBuf.position(3); + nioBuf.limit(7); + + IoBuffer buf = IoBuffer.wrap(nioBuf); + assertEquals(3, buf.position()); + assertEquals(7, buf.limit()); + assertEquals(10, buf.capacity()); + } + + @Test + public void testWrapSubArray() throws Exception { + byte[] array = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + + IoBuffer buf = IoBuffer.wrap(array, 3, 4); + assertEquals(3, buf.position()); + assertEquals(7, buf.limit()); + assertEquals(10, buf.capacity()); + + buf.clear(); + assertEquals(0, buf.position()); + assertEquals(10, buf.limit()); + assertEquals(10, buf.capacity()); + } + + @Test + public void testDuplicate() throws Exception { + IoBuffer original; + IoBuffer duplicate; + + // Test if the buffer is duplicated correctly. + original = IoBuffer.allocate(16).sweep(); + original.position(4); + original.limit(10); + duplicate = original.duplicate(); + original.put(4, (byte) 127); + assertEquals(4, duplicate.position()); + assertEquals(10, duplicate.limit()); + assertEquals(16, duplicate.capacity()); + assertNotSame(original.buf(), duplicate.buf()); + assertSame(original.buf().array(), duplicate.buf().array()); + assertEquals(127, duplicate.get(4)); + + // Test a duplicate of a duplicate. + original = IoBuffer.allocate(16); + duplicate = original.duplicate().duplicate(); + assertNotSame(original.buf(), duplicate.buf()); + assertSame(original.buf().array(), duplicate.buf().array()); + + // Try to expand. + original = IoBuffer.allocate(16); + original.setAutoExpand(true); + duplicate = original.duplicate(); + assertFalse(original.isAutoExpand()); + + try { + original.setAutoExpand(true); + fail("Derived buffers and their parent can't be expanded"); + } catch (IllegalStateException e) { + // Expected an Exception, signifies test success + assertTrue(true); + } + + try { + duplicate.setAutoExpand(true); + fail("Derived buffers and their parent can't be expanded"); + } catch (IllegalStateException e) { + // Expected an Exception, signifies test success + assertTrue(true); + } + } + + @Test + public void testSlice() throws Exception { + IoBuffer original; + IoBuffer slice; + + // Test if the buffer is sliced correctly. + original = IoBuffer.allocate(16).sweep(); + original.position(4); + original.limit(10); + slice = original.slice(); + original.put(4, (byte) 127); + assertEquals(0, slice.position()); + assertEquals(6, slice.limit()); + assertEquals(6, slice.capacity()); + assertNotSame(original.buf(), slice.buf()); + assertEquals(127, slice.get(0)); + } + + @Test + public void testReadOnlyBuffer() throws Exception { + IoBuffer original; + IoBuffer duplicate; + + // Test if the buffer is duplicated correctly. + original = IoBuffer.allocate(16).sweep(); + original.position(4); + original.limit(10); + duplicate = original.asReadOnlyBuffer(); + original.put(4, (byte) 127); + assertEquals(4, duplicate.position()); + assertEquals(10, duplicate.limit()); + assertEquals(16, duplicate.capacity()); + assertNotSame(original.buf(), duplicate.buf()); + assertEquals(127, duplicate.get(4)); + + // Try to expand. + try { + original = IoBuffer.allocate(16); + duplicate = original.asReadOnlyBuffer(); + duplicate.putString("A very very very very looooooong string", + Charset.forName("ISO-8859-1").newEncoder()); + fail("ReadOnly buffer's can't be expanded"); + } catch (ReadOnlyBufferException e) { + // Expected an Exception, signifies test success + assertTrue(true); + } + } + + @Test + public void testGetUnsigned() throws Exception { + IoBuffer buf = IoBuffer.allocate(16); + buf.put((byte) 0xA4); + buf.put((byte) 0xD0); + buf.put((byte) 0xB3); + buf.put((byte) 0xCD); + buf.flip(); + + buf.order(ByteOrder.LITTLE_ENDIAN); + + buf.mark(); + assertEquals(0xA4, buf.getUnsigned()); + buf.reset(); + assertEquals(0xD0A4, buf.getUnsignedShort()); + buf.reset(); + assertEquals(0xCDB3D0A4L, buf.getUnsignedInt()); + } + + @Test + public void testIndexOf() throws Exception { + boolean direct = false; + for (int i = 0; i < 2; i++, direct = !direct) { + IoBuffer buf = IoBuffer.allocate(16, direct); + buf.put((byte) 0x1); + buf.put((byte) 0x2); + buf.put((byte) 0x3); + buf.put((byte) 0x4); + buf.put((byte) 0x1); + buf.put((byte) 0x2); + buf.put((byte) 0x3); + buf.put((byte) 0x4); + buf.position(2); + buf.limit(5); + + assertEquals(4, buf.indexOf((byte) 0x1)); + assertEquals(-1, buf.indexOf((byte) 0x2)); + assertEquals(2, buf.indexOf((byte) 0x3)); + assertEquals(3, buf.indexOf((byte) 0x4)); + } + } + + // We need an enum with 64 values + private static enum TestEnum { + E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, E15, E16, E17, E18, E19, E20, E21, E22, E23, E24, E25, E26, E27, E28, E29, E30, E31, E32, E33, E34, E35, E36, E37, E38, E39, E40, E41, E42, E43, E44, E45, E46, E77, E48, E49, E50, E51, E52, E53, E54, E55, E56, E57, E58, E59, E60, E61, E62, E63, E64 + } + + private static enum TooBigEnum { + E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, E15, E16, E17, E18, E19, E20, E21, E22, E23, E24, E25, E26, E27, E28, E29, E30, E31, E32, E33, E34, E35, E36, E37, E38, E39, E40, E41, E42, E43, E44, E45, E46, E77, E48, E49, E50, E51, E52, E53, E54, E55, E56, E57, E58, E59, E60, E61, E62, E63, E64, E65 + } + + @Test + public void testPutEnumSet() { + IoBuffer buf = IoBuffer.allocate(8); + + // Test empty set + buf.putEnumSet(EnumSet.noneOf(TestEnum.class)); + buf.flip(); + assertEquals(0, buf.get()); + + buf.clear(); + buf.putEnumSetShort(EnumSet.noneOf(TestEnum.class)); + buf.flip(); + assertEquals(0, buf.getShort()); + + buf.clear(); + buf.putEnumSetInt(EnumSet.noneOf(TestEnum.class)); + buf.flip(); + assertEquals(0, buf.getInt()); + + buf.clear(); + buf.putEnumSetLong(EnumSet.noneOf(TestEnum.class)); + buf.flip(); + assertEquals(0, buf.getLong()); + + // Test complete set + buf.clear(); + buf.putEnumSet(EnumSet.range(TestEnum.E1, TestEnum.E8)); + buf.flip(); + assertEquals((byte) -1, buf.get()); + + buf.clear(); + buf.putEnumSetShort(EnumSet.range(TestEnum.E1, TestEnum.E16)); + buf.flip(); + assertEquals((short) -1, buf.getShort()); + + buf.clear(); + buf.putEnumSetInt(EnumSet.range(TestEnum.E1, TestEnum.E32)); + buf.flip(); + assertEquals(-1, buf.getInt()); + + buf.clear(); + buf.putEnumSetLong(EnumSet.allOf(TestEnum.class)); + buf.flip(); + assertEquals(-1L, buf.getLong()); + + // Test high bit set + buf.clear(); + buf.putEnumSet(EnumSet.of(TestEnum.E8)); + buf.flip(); + assertEquals(Byte.MIN_VALUE, buf.get()); + + buf.clear(); + buf.putEnumSetShort(EnumSet.of(TestEnum.E16)); + buf.flip(); + assertEquals(Short.MIN_VALUE, buf.getShort()); + + buf.clear(); + buf.putEnumSetInt(EnumSet.of(TestEnum.E32)); + buf.flip(); + assertEquals(Integer.MIN_VALUE, buf.getInt()); + + buf.clear(); + buf.putEnumSetLong(EnumSet.of(TestEnum.E64)); + buf.flip(); + assertEquals(Long.MIN_VALUE, buf.getLong()); + + // Test high low bits set + buf.clear(); + buf.putEnumSet(EnumSet.of(TestEnum.E1, TestEnum.E8)); + buf.flip(); + assertEquals(Byte.MIN_VALUE + 1, buf.get()); + + buf.clear(); + buf.putEnumSetShort(EnumSet.of(TestEnum.E1, TestEnum.E16)); + buf.flip(); + assertEquals(Short.MIN_VALUE + 1, buf.getShort()); + + buf.clear(); + buf.putEnumSetInt(EnumSet.of(TestEnum.E1, TestEnum.E32)); + buf.flip(); + assertEquals(Integer.MIN_VALUE + 1, buf.getInt()); + + buf.clear(); + buf.putEnumSetLong(EnumSet.of(TestEnum.E1, TestEnum.E64)); + buf.flip(); + assertEquals(Long.MIN_VALUE + 1, buf.getLong()); + } + + @Test + public void testGetEnumSet() { + IoBuffer buf = IoBuffer.allocate(8); + + // Test empty set + buf.put((byte) 0); + buf.flip(); + assertEquals(EnumSet.noneOf(TestEnum.class), + buf.getEnumSet(TestEnum.class)); + + buf.clear(); + buf.putShort((short) 0); + buf.flip(); + assertEquals(EnumSet.noneOf(TestEnum.class), + buf.getEnumSet(TestEnum.class)); + + buf.clear(); + buf.putInt(0); + buf.flip(); + assertEquals(EnumSet.noneOf(TestEnum.class), + buf.getEnumSet(TestEnum.class)); + + buf.clear(); + buf.putLong(0L); + buf.flip(); + assertEquals(EnumSet.noneOf(TestEnum.class), + buf.getEnumSet(TestEnum.class)); + + // Test complete set + buf.clear(); + buf.put((byte) -1); + buf.flip(); + assertEquals(EnumSet.range(TestEnum.E1, TestEnum.E8), + buf.getEnumSet(TestEnum.class)); + + buf.clear(); + buf.putShort((short) -1); + buf.flip(); + assertEquals(EnumSet.range(TestEnum.E1, TestEnum.E16), + buf.getEnumSetShort(TestEnum.class)); + + buf.clear(); + buf.putInt(-1); + buf.flip(); + assertEquals(EnumSet.range(TestEnum.E1, TestEnum.E32), + buf.getEnumSetInt(TestEnum.class)); + + buf.clear(); + buf.putLong(-1L); + buf.flip(); + assertEquals(EnumSet.allOf(TestEnum.class), + buf.getEnumSetLong(TestEnum.class)); + + // Test high bit set + buf.clear(); + buf.put(Byte.MIN_VALUE); + buf.flip(); + assertEquals(EnumSet.of(TestEnum.E8), buf.getEnumSet(TestEnum.class)); + + buf.clear(); + buf.putShort(Short.MIN_VALUE); + buf.flip(); + assertEquals(EnumSet.of(TestEnum.E16), + buf.getEnumSetShort(TestEnum.class)); + + buf.clear(); + buf.putInt(Integer.MIN_VALUE); + buf.flip(); + assertEquals(EnumSet.of(TestEnum.E32), + buf.getEnumSetInt(TestEnum.class)); + + buf.clear(); + buf.putLong(Long.MIN_VALUE); + buf.flip(); + assertEquals(EnumSet.of(TestEnum.E64), + buf.getEnumSetLong(TestEnum.class)); + + // Test high low bits set + buf.clear(); + byte b = Byte.MIN_VALUE + 1; + buf.put(b); + buf.flip(); + assertEquals(EnumSet.of(TestEnum.E1, TestEnum.E8), + buf.getEnumSet(TestEnum.class)); + + buf.clear(); + short s = Short.MIN_VALUE + 1; + buf.putShort(s); + buf.flip(); + assertEquals(EnumSet.of(TestEnum.E1, TestEnum.E16), + buf.getEnumSetShort(TestEnum.class)); + + buf.clear(); + buf.putInt(Integer.MIN_VALUE + 1); + buf.flip(); + assertEquals(EnumSet.of(TestEnum.E1, TestEnum.E32), + buf.getEnumSetInt(TestEnum.class)); + + buf.clear(); + buf.putLong(Long.MIN_VALUE + 1); + buf.flip(); + assertEquals(EnumSet.of(TestEnum.E1, TestEnum.E64), + buf.getEnumSetLong(TestEnum.class)); + } + + @Test + public void testBitVectorOverFlow() { + IoBuffer buf = IoBuffer.allocate(8); + try { + buf.putEnumSet(EnumSet.of(TestEnum.E9)); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // Expected an Exception, signifies test success + assertTrue(true); + } + + try { + buf.putEnumSetShort(EnumSet.of(TestEnum.E17)); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // Expected an Exception, signifies test success + assertTrue(true); + } + + try { + buf.putEnumSetInt(EnumSet.of(TestEnum.E33)); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // Expected an Exception, signifies test success + assertTrue(true); + } + + try { + buf.putEnumSetLong(EnumSet.of(TooBigEnum.E65)); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // Expected an Exception, signifies test success + assertTrue(true); + } + } + + @Test + public void testGetPutEnum() { + IoBuffer buf = IoBuffer.allocate(4); + + buf.putEnum(TestEnum.E64); + buf.flip(); + assertEquals(TestEnum.E64, buf.getEnum(TestEnum.class)); + + buf.clear(); + buf.putEnumShort(TestEnum.E64); + buf.flip(); + assertEquals(TestEnum.E64, buf.getEnumShort(TestEnum.class)); + + buf.clear(); + buf.putEnumInt(TestEnum.E64); + buf.flip(); + assertEquals(TestEnum.E64, buf.getEnumInt(TestEnum.class)); + } + + @Test + public void testGetMediumInt() { + IoBuffer buf = IoBuffer.allocate(3); + + buf.put((byte) 0x01); + buf.put((byte) 0x02); + buf.put((byte) 0x03); + assertEquals(3, buf.position()); + + buf.flip(); + assertEquals(0x010203, buf.getMediumInt()); + assertEquals(0x010203, buf.getMediumInt(0)); + buf.flip(); + assertEquals(0x010203, buf.getUnsignedMediumInt()); + assertEquals(0x010203, buf.getUnsignedMediumInt(0)); + buf.flip(); + assertEquals(0x010203, buf.getUnsignedMediumInt()); + buf.flip().order(ByteOrder.LITTLE_ENDIAN); + assertEquals(0x030201, buf.getMediumInt()); + assertEquals(0x030201, buf.getMediumInt(0)); + + // Test max medium int + buf.flip().order(ByteOrder.BIG_ENDIAN); + buf.put((byte) 0x7f); + buf.put((byte) 0xff); + buf.put((byte) 0xff); + buf.flip(); + assertEquals(0x7fffff, buf.getMediumInt()); + assertEquals(0x7fffff, buf.getMediumInt(0)); + + // Test negative number + buf.flip().order(ByteOrder.BIG_ENDIAN); + buf.put((byte) 0xff); + buf.put((byte) 0x02); + buf.put((byte) 0x03); + buf.flip(); + + assertEquals(0xffff0203, buf.getMediumInt()); + assertEquals(0xffff0203, buf.getMediumInt(0)); + buf.flip(); + + assertEquals(0x00ff0203, buf.getUnsignedMediumInt()); + assertEquals(0x00ff0203, buf.getUnsignedMediumInt(0)); + } + + @Test + public void testPutMediumInt() { + IoBuffer buf = IoBuffer.allocate(3); + + checkMediumInt(buf, 0); + checkMediumInt(buf, 1); + checkMediumInt(buf, -1); + checkMediumInt(buf, 0x7fffff); + } + + private void checkMediumInt(IoBuffer buf, int x) { + buf.putMediumInt(x); + assertEquals(3, buf.position()); + buf.flip(); + assertEquals(x, buf.getMediumInt()); + assertEquals(3, buf.position()); + + buf.putMediumInt(0, x); + assertEquals(3, buf.position()); + assertEquals(x, buf.getMediumInt(0)); + + buf.flip(); + } } diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/core/SocketOptionUnitTest.java b/src/test/java/com/google/code/yanf4j/test/unittest/core/SocketOptionUnitTest.java index 99d2a2aa7..61e468f34 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/core/SocketOptionUnitTest.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/core/SocketOptionUnitTest.java @@ -13,22 +13,28 @@ public class SocketOptionUnitTest { @Test public void testType() { - Assert.assertEquals(Integer.class, StandardSocketOption.SO_LINGER.type()); - Assert.assertEquals(Boolean.class, StandardSocketOption.SO_KEEPALIVE.type()); - Assert.assertEquals(Integer.class, StandardSocketOption.SO_RCVBUF.type()); - Assert.assertEquals(Integer.class, StandardSocketOption.SO_SNDBUF.type()); - Assert.assertEquals(Boolean.class, StandardSocketOption.SO_REUSEADDR.type()); - Assert.assertEquals(Boolean.class, StandardSocketOption.TCP_NODELAY.type()); + Assert.assertEquals(Integer.class, + StandardSocketOption.SO_LINGER.type()); + Assert.assertEquals(Boolean.class, + StandardSocketOption.SO_KEEPALIVE.type()); + Assert.assertEquals(Integer.class, + StandardSocketOption.SO_RCVBUF.type()); + Assert.assertEquals(Integer.class, + StandardSocketOption.SO_SNDBUF.type()); + Assert.assertEquals(Boolean.class, + StandardSocketOption.SO_REUSEADDR.type()); + Assert.assertEquals(Boolean.class, + StandardSocketOption.TCP_NODELAY.type()); } - + @Test - public void testPutInMap(){ - Map map=new HashMap(); + public void testPutInMap() { + Map map = new HashMap(); map.put(StandardSocketOption.SO_KEEPALIVE, true); map.put(StandardSocketOption.SO_RCVBUF, 4096); map.put(StandardSocketOption.SO_SNDBUF, 4096); map.put(StandardSocketOption.TCP_NODELAY, false); - + Assert.assertEquals(4096, map.get(StandardSocketOption.SO_RCVBUF)); Assert.assertEquals(4096, map.get(StandardSocketOption.SO_SNDBUF)); Assert.assertEquals(false, map.get(StandardSocketOption.TCP_NODELAY)); diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/AbstractControllerUnitTest.java b/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/AbstractControllerUnitTest.java index 126445d5b..f396c86e9 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/AbstractControllerUnitTest.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/AbstractControllerUnitTest.java @@ -13,8 +13,6 @@ import com.google.code.yanf4j.core.impl.StandardSocketOption; import com.google.code.yanf4j.nio.TCPController; - - /** * * @@ -25,151 +23,143 @@ */ public abstract class AbstractControllerUnitTest { - protected AbstractController controller; - - - @Test - public void testConfigThreadCount() throws Exception { - Configuration configuration = new Configuration(); - configuration.setReadThreadCount(10); - configuration.setWriteThreadCount(1); - configuration.setDispatchMessageThreadCount(11); - this.controller = new TCPController(configuration); - this.controller.setHandler(new HandlerAdapter()); - Assert.assertEquals(10, this.controller.getReadThreadCount()); - Assert.assertEquals(1, this.controller.getWriteThreadCount()); - Assert.assertEquals(11, this.controller.getDispatchMessageThreadCount()); - - this.controller.setReadThreadCount(0); - this.controller.setWriteThreadCount(0); - this.controller.setDispatchMessageThreadCount(0); - - Assert.assertEquals(0, this.controller.getReadThreadCount()); - Assert.assertEquals(0, this.controller.getWriteThreadCount()); - Assert.assertEquals(0, this.controller.getDispatchMessageThreadCount()); - try { - this.controller.setReadThreadCount(-1); - Assert.fail(); - } - catch (IllegalArgumentException e) { - - } - try { - this.controller.setWriteThreadCount(-1); - Assert.fail(); - } - catch (IllegalArgumentException e) { - - } - try { - this.controller.setDispatchMessageThreadCount(-1); - Assert.fail(); - } - catch (IllegalArgumentException e) { - - } - this.controller.start(); - try { - this.controller.setReadThreadCount(1); - Assert.fail(); - } - catch (IllegalStateException e) { - - } - - try { - this.controller.setWriteThreadCount(1); - Assert.fail(); - } - catch (IllegalStateException e) { - - } - - try { - this.controller.setDispatchMessageThreadCount(1); - Assert.fail(); - } - catch (IllegalStateException e) { - - } - - } - - - @Test - public void testSetSocketOption() throws Exception { - this.controller = new TCPController(new Configuration()); - this.controller.setSocketOption(StandardSocketOption.SO_KEEPALIVE, true); - Assert.assertEquals(true, this.controller.getSocketOption(StandardSocketOption.SO_KEEPALIVE)); - - this.controller.setSocketOption(StandardSocketOption.SO_RCVBUF, 4096); - Assert.assertEquals((Integer)4096, this.controller.getSocketOption(StandardSocketOption.SO_RCVBUF)); - - try { - this.controller.setSocketOption(null, 3); - Assert.fail(); - } - catch (NullPointerException e) { - Assert.assertEquals("Null socketOption", e.getMessage()); - } - try { - this.controller.setSocketOption(StandardSocketOption.SO_RCVBUF, null); - Assert.fail(); - } - catch (NullPointerException e) { - Assert.assertEquals("Null value", e.getMessage()); - } - } - - - @Test - public void testNoHandler() throws Exception { - this.controller = new TCPController(new Configuration()); - Assert.assertNull(this.controller.getHandler()); - try { - this.controller.start(); - Assert.fail(); - } - catch (IOException e) { - Assert.assertEquals("The handler is null", e.getMessage()); - } - } - - - @Test - public void testNoCodecFactory() throws Exception { - this.controller = new TCPController(new Configuration()); - this.controller.setHandler(new HandlerAdapter()); - Assert.assertNull(this.controller.getCodecFactory()); - this.controller.start(); - Assert.assertTrue(this.controller.getCodecFactory() instanceof ByteBufferCodecFactory); - } - - - @Test - public void testConfig() { - Configuration configuration = new Configuration(); - this.controller = new TCPController(configuration); - Assert.assertEquals(configuration.isHandleReadWriteConcurrently(), this.controller.isHandleReadWriteConcurrently()); - this.controller.setHandleReadWriteConcurrently(false); - Assert.assertFalse(this.controller.isHandleReadWriteConcurrently()); - - this.controller.setSessionIdleTimeout(100000); - Assert.assertEquals(100000, this.controller.getSessionIdleTimeout()); - this.controller.setSessionTimeout(5000); - Assert.assertEquals(5000, this.controller.getSessionTimeout()); - - this.controller.setSoTimeout(9000); - Assert.assertEquals(9000, this.controller.getSoTimeout()); - - } - - - @After - public void tearDown() throws Exception { - if (this.controller != null) { - this.controller.stop(); - } - } + protected AbstractController controller; + + @Test + public void testConfigThreadCount() throws Exception { + Configuration configuration = new Configuration(); + configuration.setReadThreadCount(10); + configuration.setWriteThreadCount(1); + configuration.setDispatchMessageThreadCount(11); + this.controller = new TCPController(configuration); + this.controller.setHandler(new HandlerAdapter()); + Assert.assertEquals(10, this.controller.getReadThreadCount()); + Assert.assertEquals(1, this.controller.getWriteThreadCount()); + Assert.assertEquals(11, + this.controller.getDispatchMessageThreadCount()); + + this.controller.setReadThreadCount(0); + this.controller.setWriteThreadCount(0); + this.controller.setDispatchMessageThreadCount(0); + + Assert.assertEquals(0, this.controller.getReadThreadCount()); + Assert.assertEquals(0, this.controller.getWriteThreadCount()); + Assert.assertEquals(0, this.controller.getDispatchMessageThreadCount()); + try { + this.controller.setReadThreadCount(-1); + Assert.fail(); + } catch (IllegalArgumentException e) { + + } + try { + this.controller.setWriteThreadCount(-1); + Assert.fail(); + } catch (IllegalArgumentException e) { + + } + try { + this.controller.setDispatchMessageThreadCount(-1); + Assert.fail(); + } catch (IllegalArgumentException e) { + + } + this.controller.start(); + try { + this.controller.setReadThreadCount(1); + Assert.fail(); + } catch (IllegalStateException e) { + + } + + try { + this.controller.setWriteThreadCount(1); + Assert.fail(); + } catch (IllegalStateException e) { + + } + + try { + this.controller.setDispatchMessageThreadCount(1); + Assert.fail(); + } catch (IllegalStateException e) { + + } + + } + + @Test + public void testSetSocketOption() throws Exception { + this.controller = new TCPController(new Configuration()); + this.controller.setSocketOption(StandardSocketOption.SO_KEEPALIVE, + true); + Assert.assertEquals(true, this.controller + .getSocketOption(StandardSocketOption.SO_KEEPALIVE)); + + this.controller.setSocketOption(StandardSocketOption.SO_RCVBUF, 4096); + Assert.assertEquals((Integer) 4096, this.controller + .getSocketOption(StandardSocketOption.SO_RCVBUF)); + + try { + this.controller.setSocketOption(null, 3); + Assert.fail(); + } catch (NullPointerException e) { + Assert.assertEquals("Null socketOption", e.getMessage()); + } + try { + this.controller.setSocketOption(StandardSocketOption.SO_RCVBUF, + null); + Assert.fail(); + } catch (NullPointerException e) { + Assert.assertEquals("Null value", e.getMessage()); + } + } + + @Test + public void testNoHandler() throws Exception { + this.controller = new TCPController(new Configuration()); + Assert.assertNull(this.controller.getHandler()); + try { + this.controller.start(); + Assert.fail(); + } catch (IOException e) { + Assert.assertEquals("The handler is null", e.getMessage()); + } + } + + @Test + public void testNoCodecFactory() throws Exception { + this.controller = new TCPController(new Configuration()); + this.controller.setHandler(new HandlerAdapter()); + Assert.assertNull(this.controller.getCodecFactory()); + this.controller.start(); + Assert.assertTrue(this.controller + .getCodecFactory() instanceof ByteBufferCodecFactory); + } + + @Test + public void testConfig() { + Configuration configuration = new Configuration(); + this.controller = new TCPController(configuration); + Assert.assertEquals(configuration.isHandleReadWriteConcurrently(), + this.controller.isHandleReadWriteConcurrently()); + this.controller.setHandleReadWriteConcurrently(false); + Assert.assertFalse(this.controller.isHandleReadWriteConcurrently()); + + this.controller.setSessionIdleTimeout(100000); + Assert.assertEquals(100000, this.controller.getSessionIdleTimeout()); + this.controller.setSessionTimeout(5000); + Assert.assertEquals(5000, this.controller.getSessionTimeout()); + + this.controller.setSoTimeout(9000); + Assert.assertEquals(9000, this.controller.getSoTimeout()); + + } + + @After + public void tearDown() throws Exception { + if (this.controller != null) { + this.controller.stop(); + } + } } diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/ByteBufferCodecFactoryUnitTest.java b/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/ByteBufferCodecFactoryUnitTest.java index 5fe24ad99..5746960d4 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/ByteBufferCodecFactoryUnitTest.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/ByteBufferCodecFactoryUnitTest.java @@ -8,7 +8,6 @@ import com.google.code.yanf4j.core.CodecFactory.Encoder; import com.google.code.yanf4j.core.impl.ByteBufferCodecFactory; - /** * * @@ -19,59 +18,59 @@ */ public class ByteBufferCodecFactoryUnitTest { - ByteBufferCodecFactory codecFactory; - - - @Before - public void setUp() { - this.codecFactory = new ByteBufferCodecFactory(); - } - - - @Test - public void testEncodeNormal() throws Exception { - Encoder encoder = this.codecFactory.getEncoder(); - Assert.assertNotNull(encoder); - IoBuffer buffer = encoder.encode(IoBuffer.wrap("hello".getBytes("utf-8")), null); - Assert.assertNotNull(buffer); - Assert.assertTrue(buffer.hasRemaining()); - Assert.assertArrayEquals("hello".getBytes("utf-8"), buffer.array()); - - } - - - @Test - public void testEncodeEmpty() throws Exception { - Encoder encoder = this.codecFactory.getEncoder(); - Assert.assertNull(encoder.encode(null, null)); - Assert.assertEquals(IoBuffer.allocate(0), encoder.encode(IoBuffer.allocate(0), null)); - } - - - @Test - public void decodeNormal() throws Exception { - Encoder encoder = this.codecFactory.getEncoder(); - Assert.assertNotNull(encoder); - IoBuffer buffer = encoder.encode(IoBuffer.wrap("hello".getBytes("utf-8")), null); - - IoBuffer decodeBuffer = (IoBuffer) this.codecFactory.getDecoder().decode(buffer, null); - Assert.assertEquals(IoBuffer.wrap("hello".getBytes("utf-8")), decodeBuffer); - } - - - @Test - public void decodeEmpty() throws Exception { - Assert.assertNull(this.codecFactory.getDecoder().decode(null, null)); - Assert.assertEquals(IoBuffer.allocate(0), this.codecFactory.getDecoder().decode(IoBuffer.allocate(0), null)); - } - - - @Test - public void testDirectEncoder() throws Exception { - this.codecFactory = new ByteBufferCodecFactory(true); - IoBuffer msg = IoBuffer.allocate(100); - IoBuffer buffer = this.codecFactory.getEncoder().encode(msg, null); - Assert.assertTrue(buffer.isDirect()); - } + ByteBufferCodecFactory codecFactory; + + @Before + public void setUp() { + this.codecFactory = new ByteBufferCodecFactory(); + } + + @Test + public void testEncodeNormal() throws Exception { + Encoder encoder = this.codecFactory.getEncoder(); + Assert.assertNotNull(encoder); + IoBuffer buffer = encoder + .encode(IoBuffer.wrap("hello".getBytes("utf-8")), null); + Assert.assertNotNull(buffer); + Assert.assertTrue(buffer.hasRemaining()); + Assert.assertArrayEquals("hello".getBytes("utf-8"), buffer.array()); + + } + + @Test + public void testEncodeEmpty() throws Exception { + Encoder encoder = this.codecFactory.getEncoder(); + Assert.assertNull(encoder.encode(null, null)); + Assert.assertEquals(IoBuffer.allocate(0), + encoder.encode(IoBuffer.allocate(0), null)); + } + + @Test + public void decodeNormal() throws Exception { + Encoder encoder = this.codecFactory.getEncoder(); + Assert.assertNotNull(encoder); + IoBuffer buffer = encoder + .encode(IoBuffer.wrap("hello".getBytes("utf-8")), null); + + IoBuffer decodeBuffer = (IoBuffer) this.codecFactory.getDecoder() + .decode(buffer, null); + Assert.assertEquals(IoBuffer.wrap("hello".getBytes("utf-8")), + decodeBuffer); + } + + @Test + public void decodeEmpty() throws Exception { + Assert.assertNull(this.codecFactory.getDecoder().decode(null, null)); + Assert.assertEquals(IoBuffer.allocate(0), this.codecFactory.getDecoder() + .decode(IoBuffer.allocate(0), null)); + } + + @Test + public void testDirectEncoder() throws Exception { + this.codecFactory = new ByteBufferCodecFactory(true); + IoBuffer msg = IoBuffer.allocate(100); + IoBuffer buffer = this.codecFactory.getEncoder().encode(msg, null); + Assert.assertTrue(buffer.isDirect()); + } } diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/FutureImplUnitTest.java b/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/FutureImplUnitTest.java index dca4d7571..d74bda3b0 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/FutureImplUnitTest.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/FutureImplUnitTest.java @@ -12,7 +12,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; - /** * * @@ -24,115 +23,106 @@ public class FutureImplUnitTest { - private static final Logger log = LoggerFactory.getLogger(FutureImplUnitTest.class); - - private static final class NotifyFutureRunner implements Runnable { - FutureImpl future; - long sleepTime; - Throwable throwable; - - - public NotifyFutureRunner(FutureImpl future, long sleepTime, Throwable throwable) { - super(); - this.future = future; - this.sleepTime = sleepTime; - this.throwable = throwable; - } - - - public void run() { - try { - Thread.sleep(this.sleepTime); - if (this.throwable != null) { - this.future.failure(this.throwable); - } - else { - this.future.setResult(true); - } - } - catch (Exception e) { - throw new RuntimeException(e); - } - } - } - - - @Test - public void testGet() throws Exception { - FutureImpl future = new FutureImpl(); - new Thread(new NotifyFutureRunner(future, 2000, null)).start(); - boolean result = future.get(); - Assert.assertTrue(result); - Assert.assertTrue(future.isDone()); - Assert.assertFalse(future.isCancelled()); - } - - - @Test - public void testGetImmediately() throws Exception { - FutureImpl future = new FutureImpl(); - future.setResult(true); - boolean result = future.get(); - Assert.assertTrue(result); - Assert.assertTrue(future.isDone()); - Assert.assertFalse(future.isCancelled()); - } - - - @Test - public void testGetException() throws Exception { - FutureImpl future = new FutureImpl(); - new Thread(new NotifyFutureRunner(future, 2000, new IOException("hello"))).start(); - try { - future.get(); - Assert.fail(); - } - catch (ExecutionException e) { - Assert.assertEquals("hello", e.getCause().getMessage()); - - } - Assert.assertTrue(future.isDone()); - Assert.assertFalse(future.isCancelled()); - - } - - - @Test - public void testCancel() throws Exception { - final FutureImpl future = new FutureImpl(); - new Thread(new Runnable() { - public void run() { - try { - Thread.sleep(3000); - future.cancel(true); - } - catch (Exception e) { - log.error(e.getMessage(), e); - } - } - }).start(); - try { - future.get(); - Assert.fail(); - } - catch (CancellationException e) { - Assert.assertTrue(true); - - } - Assert.assertTrue(future.isDone()); - Assert.assertTrue(future.isCancelled()); - } - - - @Test - public void testGetTimeout() throws Exception { - FutureImpl future = new FutureImpl(); - try { - future.get(1000, TimeUnit.MILLISECONDS); - Assert.fail(); - } - catch (TimeoutException e) { - Assert.assertTrue(true); - } - } + private static final Logger log = LoggerFactory + .getLogger(FutureImplUnitTest.class); + + private static final class NotifyFutureRunner implements Runnable { + FutureImpl future; + long sleepTime; + Throwable throwable; + + public NotifyFutureRunner(FutureImpl future, long sleepTime, + Throwable throwable) { + super(); + this.future = future; + this.sleepTime = sleepTime; + this.throwable = throwable; + } + + public void run() { + try { + Thread.sleep(this.sleepTime); + if (this.throwable != null) { + this.future.failure(this.throwable); + } else { + this.future.setResult(true); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + + @Test + public void testGet() throws Exception { + FutureImpl future = new FutureImpl(); + new Thread(new NotifyFutureRunner(future, 2000, null)).start(); + boolean result = future.get(); + Assert.assertTrue(result); + Assert.assertTrue(future.isDone()); + Assert.assertFalse(future.isCancelled()); + } + + @Test + public void testGetImmediately() throws Exception { + FutureImpl future = new FutureImpl(); + future.setResult(true); + boolean result = future.get(); + Assert.assertTrue(result); + Assert.assertTrue(future.isDone()); + Assert.assertFalse(future.isCancelled()); + } + + @Test + public void testGetException() throws Exception { + FutureImpl future = new FutureImpl(); + new Thread( + new NotifyFutureRunner(future, 2000, new IOException("hello"))) + .start(); + try { + future.get(); + Assert.fail(); + } catch (ExecutionException e) { + Assert.assertEquals("hello", e.getCause().getMessage()); + + } + Assert.assertTrue(future.isDone()); + Assert.assertFalse(future.isCancelled()); + + } + + @Test + public void testCancel() throws Exception { + final FutureImpl future = new FutureImpl(); + new Thread(new Runnable() { + public void run() { + try { + Thread.sleep(3000); + future.cancel(true); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + } + }).start(); + try { + future.get(); + Assert.fail(); + } catch (CancellationException e) { + Assert.assertTrue(true); + + } + Assert.assertTrue(future.isDone()); + Assert.assertTrue(future.isCancelled()); + } + + @Test + public void testGetTimeout() throws Exception { + FutureImpl future = new FutureImpl(); + try { + future.get(1000, TimeUnit.MILLISECONDS); + Assert.fail(); + } catch (TimeoutException e) { + Assert.assertTrue(true); + } + } } diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/FutureLockImplUnitTest.java b/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/FutureLockImplUnitTest.java index aca2b669a..46254b023 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/FutureLockImplUnitTest.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/FutureLockImplUnitTest.java @@ -12,7 +12,6 @@ import com.google.code.yanf4j.core.impl.FutureLockImpl; - /** * * @@ -24,113 +23,103 @@ public class FutureLockImplUnitTest { - private static final class NotifyFutureRunner implements Runnable { - FutureLockImpl future; - long sleepTime; - Throwable throwable; - - - public NotifyFutureRunner(FutureLockImpl future, long sleepTime, Throwable throwable) { - super(); - this.future = future; - this.sleepTime = sleepTime; - this.throwable = throwable; - } - - - public void run() { - try { - Thread.sleep(this.sleepTime); - if (this.throwable != null) { - this.future.failure(this.throwable); - } - else { - this.future.setResult(true); - } - } - catch (Exception e) { - throw new RuntimeException(e); - } - } - } - - - @Test - public void testGet() throws Exception { - FutureLockImpl future = new FutureLockImpl(); - new Thread(new NotifyFutureRunner(future, 2000, null)).start(); - boolean result = future.get(); - Assert.assertTrue(result); - Assert.assertTrue(future.isDone()); - Assert.assertFalse(future.isCancelled()); - } - - - @Test - public void testGetImmediately() throws Exception { - FutureLockImpl future = new FutureLockImpl(); - future.setResult(true); - boolean result = future.get(); - Assert.assertTrue(result); - Assert.assertTrue(future.isDone()); - Assert.assertFalse(future.isCancelled()); - } - - - @Test - public void testGetException() throws Exception { - FutureLockImpl future = new FutureLockImpl(); - new Thread(new NotifyFutureRunner(future, 2000, new IOException("hello"))).start(); - try { - future.get(); - Assert.fail(); - } - catch (ExecutionException e) { - Assert.assertEquals("hello", e.getCause().getMessage()); - - } - Assert.assertTrue(future.isDone()); - Assert.assertFalse(future.isCancelled()); - - } - - - @Test - public void testCancel() throws Exception { - final FutureLockImpl future = new FutureLockImpl(); - new Thread(new Runnable() { - public void run() { - try { - Thread.sleep(3000); - future.cancel(true); - } - catch (Exception e) { - e.printStackTrace(); - } - } - }).start(); - try { - future.get(); - Assert.fail(); - } - catch (CancellationException e) { - Assert.assertTrue(true); - - } - Assert.assertTrue(future.isDone()); - Assert.assertTrue(future.isCancelled()); - } - - - @Test - public void testGetTimeout() throws Exception { - FutureLockImpl future = new FutureLockImpl(); - try { - future.get(1000, TimeUnit.MILLISECONDS); - Assert.fail(); - } - catch (TimeoutException e) { - Assert.assertTrue(true); - } - } + private static final class NotifyFutureRunner implements Runnable { + FutureLockImpl future; + long sleepTime; + Throwable throwable; + + public NotifyFutureRunner(FutureLockImpl future, + long sleepTime, Throwable throwable) { + super(); + this.future = future; + this.sleepTime = sleepTime; + this.throwable = throwable; + } + + public void run() { + try { + Thread.sleep(this.sleepTime); + if (this.throwable != null) { + this.future.failure(this.throwable); + } else { + this.future.setResult(true); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + + @Test + public void testGet() throws Exception { + FutureLockImpl future = new FutureLockImpl(); + new Thread(new NotifyFutureRunner(future, 2000, null)).start(); + boolean result = future.get(); + Assert.assertTrue(result); + Assert.assertTrue(future.isDone()); + Assert.assertFalse(future.isCancelled()); + } + + @Test + public void testGetImmediately() throws Exception { + FutureLockImpl future = new FutureLockImpl(); + future.setResult(true); + boolean result = future.get(); + Assert.assertTrue(result); + Assert.assertTrue(future.isDone()); + Assert.assertFalse(future.isCancelled()); + } + + @Test + public void testGetException() throws Exception { + FutureLockImpl future = new FutureLockImpl(); + new Thread( + new NotifyFutureRunner(future, 2000, new IOException("hello"))) + .start(); + try { + future.get(); + Assert.fail(); + } catch (ExecutionException e) { + Assert.assertEquals("hello", e.getCause().getMessage()); + + } + Assert.assertTrue(future.isDone()); + Assert.assertFalse(future.isCancelled()); + + } + + @Test + public void testCancel() throws Exception { + final FutureLockImpl future = new FutureLockImpl(); + new Thread(new Runnable() { + public void run() { + try { + Thread.sleep(3000); + future.cancel(true); + } catch (Exception e) { + e.printStackTrace(); + } + } + }).start(); + try { + future.get(); + Assert.fail(); + } catch (CancellationException e) { + Assert.assertTrue(true); + + } + Assert.assertTrue(future.isDone()); + Assert.assertTrue(future.isCancelled()); + } + + @Test + public void testGetTimeout() throws Exception { + FutureLockImpl future = new FutureLockImpl(); + try { + future.get(1000, TimeUnit.MILLISECONDS); + Assert.fail(); + } catch (TimeoutException e) { + Assert.assertTrue(true); + } + } } diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/PoolDispatcherUnitTest.java b/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/PoolDispatcherUnitTest.java index 6cb5fb765..f8807e35b 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/PoolDispatcherUnitTest.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/PoolDispatcherUnitTest.java @@ -25,7 +25,8 @@ public class PoolDispatcherUnitTest { @Before public void setUp() { - this.dispatcher = new PoolDispatcher(10, 60, TimeUnit.SECONDS, new ThreadPoolExecutor.AbortPolicy(), "test"); + this.dispatcher = new PoolDispatcher(10, 60, TimeUnit.SECONDS, + new ThreadPoolExecutor.AbortPolicy(), "test"); } @After @@ -58,7 +59,7 @@ public void testDispatchNull() throws Exception { @Test public void testDispatcherStop() throws Exception { - this.dispatcher.stop(); + this.dispatcher.stop(); TestRunner runner = new TestRunner(); this.dispatcher.dispatch(runner); Thread.sleep(1000); @@ -67,8 +68,8 @@ public void testDispatcherStop() throws Exception { @Test(expected = RejectedExecutionException.class) public void testDispatchReject() throws Exception { - this.dispatcher = new PoolDispatcher(1, 1, 1, 60, TimeUnit.SECONDS, new ThreadPoolExecutor.AbortPolicy(), - "test"); + this.dispatcher = new PoolDispatcher(1, 1, 1, 60, TimeUnit.SECONDS, + new ThreadPoolExecutor.AbortPolicy(), "test"); this.dispatcher.dispatch(new Runnable() { public void run() { while (!Thread.currentThread().isInterrupted()) { diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/TextLineCodecFactoryUnitTest.java b/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/TextLineCodecFactoryUnitTest.java index 84ca883cf..0ec1b88c7 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/TextLineCodecFactoryUnitTest.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/core/impl/TextLineCodecFactoryUnitTest.java @@ -41,7 +41,8 @@ public void testEncodeNormal() throws Exception { public void testEncodeEmpty() throws Exception { Encoder encoder = this.textLineCodecFactory.getEncoder(); Assert.assertNull(encoder.encode(null, null)); - Assert.assertEquals(TextLineCodecFactory.SPLIT, encoder.encode("", null)); + Assert.assertEquals(TextLineCodecFactory.SPLIT, + encoder.encode("", null)); } @Test @@ -50,14 +51,17 @@ public void decodeNormal() throws Exception { Assert.assertNotNull(encoder); IoBuffer buffer = encoder.encode("hello", null); - String str = (String) this.textLineCodecFactory.getDecoder().decode(buffer, null); + String str = (String) this.textLineCodecFactory.getDecoder() + .decode(buffer, null); Assert.assertEquals("hello", str); } @Test public void decodeEmpty() throws Exception { - Assert.assertNull(this.textLineCodecFactory.getDecoder().decode(null, null)); - Assert.assertEquals("", this.textLineCodecFactory.getDecoder().decode(TextLineCodecFactory.SPLIT, null)); + Assert.assertNull( + this.textLineCodecFactory.getDecoder().decode(null, null)); + Assert.assertEquals("", this.textLineCodecFactory.getDecoder() + .decode(TextLineCodecFactory.SPLIT, null)); } } diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/MockSelectableChannel.java b/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/MockSelectableChannel.java index ec58b38bb..5b1bf0a6b 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/MockSelectableChannel.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/MockSelectableChannel.java @@ -7,7 +7,6 @@ import java.nio.channels.Selector; import java.nio.channels.spi.SelectorProvider; - /** * * @@ -18,76 +17,69 @@ */ public class MockSelectableChannel extends SelectableChannel { - Selector selector; - int ops; - Object attch; - MockSelectionKey selectionKey = new MockSelectionKey(); - - - @Override - public Object blockingLock() { - // TODO Auto-generated method stub - return null; - } - - - @Override - public SelectableChannel configureBlocking(boolean block) throws IOException { - // TODO Auto-generated method stub - return null; - } - - - @Override - public boolean isBlocking() { - // TODO Auto-generated method stub - return false; - } - - - @Override - public boolean isRegistered() { - // TODO Auto-generated method stub - return false; - } - - - @Override - public SelectionKey keyFor(Selector sel) { - // TODO Auto-generated method stub - return null; - } - - - @Override - public SelectorProvider provider() { - // TODO Auto-generated method stub - return null; - } - - - @Override - public SelectionKey register(Selector sel, int ops, Object att) throws ClosedChannelException { - this.selector = sel; - this.ops = ops; - this.attch = att; - this.selectionKey.channel = this; - this.selectionKey.selector = sel; - return this.selectionKey; - } - - - @Override - public int validOps() { - // TODO Auto-generated method stub - return 0; - } - - - @Override - protected void implCloseChannel() throws IOException { - // TODO Auto-generated method stub - - } + Selector selector; + int ops; + Object attch; + MockSelectionKey selectionKey = new MockSelectionKey(); + + @Override + public Object blockingLock() { + // TODO Auto-generated method stub + return null; + } + + @Override + public SelectableChannel configureBlocking(boolean block) + throws IOException { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isBlocking() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isRegistered() { + // TODO Auto-generated method stub + return false; + } + + @Override + public SelectionKey keyFor(Selector sel) { + // TODO Auto-generated method stub + return null; + } + + @Override + public SelectorProvider provider() { + // TODO Auto-generated method stub + return null; + } + + @Override + public SelectionKey register(Selector sel, int ops, Object att) + throws ClosedChannelException { + this.selector = sel; + this.ops = ops; + this.attch = att; + this.selectionKey.channel = this; + this.selectionKey.selector = sel; + return this.selectionKey; + } + + @Override + public int validOps() { + // TODO Auto-generated method stub + return 0; + } + + @Override + protected void implCloseChannel() throws IOException { + // TODO Auto-generated method stub + + } } diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/MockSelectionKey.java b/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/MockSelectionKey.java index 8a9cbed24..2e12f46d6 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/MockSelectionKey.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/MockSelectionKey.java @@ -4,7 +4,6 @@ import java.nio.channels.SelectionKey; import java.nio.channels.Selector; - /** * * @@ -15,53 +14,46 @@ */ public class MockSelectionKey extends SelectionKey { - MockSelectableChannel channel; - int interestOps; - boolean valid = true; - Selector selector; - - - @Override - public void cancel() { - this.valid = false; - - } - - - @Override - public SelectableChannel channel() { - return this.channel; - } - - - @Override - public int interestOps() { - return this.interestOps; - } - - - @Override - public SelectionKey interestOps(int ops) { - this.interestOps = ops; - return this; - } - - - @Override - public boolean isValid() { - return this.valid; - } - - - @Override - public int readyOps() { - return this.interestOps; - } - - - @Override - public Selector selector() { - return this.selector; - } + MockSelectableChannel channel; + int interestOps; + boolean valid = true; + Selector selector; + + @Override + public void cancel() { + this.valid = false; + + } + + @Override + public SelectableChannel channel() { + return this.channel; + } + + @Override + public int interestOps() { + return this.interestOps; + } + + @Override + public SelectionKey interestOps(int ops) { + this.interestOps = ops; + return this; + } + + @Override + public boolean isValid() { + return this.valid; + } + + @Override + public int readyOps() { + return this.interestOps; + } + + @Override + public Selector selector() { + return this.selector; + } } diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/ReactorUnitTest.java b/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/ReactorUnitTest.java index b33eea159..0ab61ec2a 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/ReactorUnitTest.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/ReactorUnitTest.java @@ -20,7 +20,6 @@ import com.google.code.yanf4j.nio.impl.Reactor; import com.google.code.yanf4j.nio.impl.SelectorManager; - /** * * @@ -31,216 +30,206 @@ */ public class ReactorUnitTest { - private Reactor reactor; - private SelectorManager selectorManager; - - - @Before - public void setUp() throws Exception { - Configuration configuration = new Configuration(); - TCPController controller = new TCPController(configuration); - this.selectorManager = new SelectorManager(1, controller, configuration); - this.selectorManager.start(); - this.reactor = this.selectorManager.getReactorByIndex(0); - controller.setSessionTimeout(1000); - controller.getConfiguration().setSessionIdleTimeout(1000); - } - - - @Test - public void testRegisterOpenChannel() throws Exception { - MockSelectableChannel channel = new MockSelectableChannel(); - channel.selectionKey = new MockSelectionKey(); - this.reactor.registerChannel(channel, 1, "hello"); - Thread.sleep(Reactor.DEFAULT_WAIT * 3); - Assert.assertSame(this.reactor.getSelector(), channel.selector); - Assert.assertSame(this.reactor.getSelector(), channel.selectionKey.selector); - Assert.assertEquals(1, channel.ops); - Assert.assertEquals("hello", channel.attch); - } - - - @Test - public void testRegisterCloseChannel() throws Exception { - MockSelectableChannel channel = new MockSelectableChannel(); - channel.close(); - this.reactor.registerChannel(channel, 1, "hello"); - Thread.sleep(Reactor.DEFAULT_WAIT * 3); - Assert.assertNull(channel.selector); - Assert.assertEquals(0, channel.ops); - Assert.assertNull(channel.attch); - } - - - @Test - public void testRegisterOpenSession() throws Exception { - IMocksControl control = EasyMock.createControl(); - NioSession session = control.createMock(NioSession.class); - session.onEvent(EventType.ENABLE_READ, this.reactor.getSelector()); - EasyMock.expectLastCall(); - EasyMock.expect(session.isClosed()).andReturn(false); - - control.replay(); - this.reactor.registerSession(session, EventType.ENABLE_READ); - Thread.sleep(Reactor.DEFAULT_WAIT * 3); - control.verify(); - } - - - @Test - public void testRegisterCloseSession() throws Exception { - IMocksControl control = EasyMock.createControl(); - NioSession session = control.createMock(NioSession.class); - EasyMock.expect(session.isClosed()).andReturn(true); - control.replay(); - this.reactor.registerSession(session, EventType.ENABLE_READ); - Thread.sleep(Reactor.DEFAULT_WAIT * 3); - control.verify(); - } - - - @Test - public void testDispatchEventAllValid() throws Exception { - IMocksControl control = EasyMock.createControl(); - Set keySet = new HashSet(); - addReadableKey(keySet, control, this.reactor.getSelector()); - addWritableKey(keySet, control, this.reactor.getSelector()); - control.replay(); - this.reactor.dispatchEvent(keySet); - Assert.assertEquals(0, keySet.size()); - control.verify(); - } - - - @Test - public void testDispatchEventSomeInValid() throws Exception { - IMocksControl control = EasyMock.createControl(); - Set keySet = new HashSet(); - addInvalidKey(keySet); - addWritableKey(keySet, control, this.reactor.getSelector()); - control.replay(); - this.reactor.dispatchEvent(keySet); - Assert.assertEquals(0, keySet.size()); - control.verify(); - } - - - @Test - public void testPostSelectOneTimeout() { - IMocksControl mocksControl = EasyMock.createControl(); - Set selectedKeys = new HashSet(); - Set allKeys = new HashSet(); - addTimeoutKey(mocksControl, allKeys); - allKeys.addAll(selectedKeys); - - mocksControl.replay(); - this.reactor.postSelect(selectedKeys, allKeys); - mocksControl.verify(); - - } - - - private void addTimeoutKey(IMocksControl mocksControl, Set allKeys) { - MockSelectionKey key = new MockSelectionKey(); - NioSession session = mocksControl.createMock(NioSession.class); - key.attach(session); - // �ж�session�Ƿ���ڣ�����Ϊ���� - EasyMock.expect(session.isExpired()).andReturn(true); - // ���ھͻ����onSessionExpired�����ر����� - // ͬʱ��expired��session�����ж�idle - session.onEvent(EventType.EXPIRED, this.reactor.getSelector()); - EasyMock.expectLastCall(); - session.close(); - EasyMock.expectLastCall(); - - allKeys.add(key); - } - - - @Test - public void testPostSelectOneIdle() { - IMocksControl mocksControl = EasyMock.createControl(); - Set selectedKeys = new HashSet(); - Set allKeys = new HashSet(); - addIdleKey(mocksControl, allKeys); - allKeys.addAll(selectedKeys); - - mocksControl.replay(); - this.reactor.postSelect(selectedKeys, allKeys); - mocksControl.verify(); - - } - - - @Test - public void testPostSelectMoreKeys() { - IMocksControl mocksControl = EasyMock.createControl(); - Set selectedKeys = new HashSet(); - Set allKeys = new HashSet(); - addIdleKey(mocksControl, allKeys); - addTimeoutKey(mocksControl, allKeys); - selectedKeys.add(new MockSelectionKey()); - selectedKeys.add(new MockSelectionKey()); - allKeys.addAll(selectedKeys); - - mocksControl.replay(); - this.reactor.postSelect(selectedKeys, allKeys); - mocksControl.verify(); - } - - - private void addIdleKey(IMocksControl mocksControl, Set allKeys) { - MockSelectionKey key = new MockSelectionKey(); - NioSession session = mocksControl.createMock(NioSession.class); - key.attach(session); - // session - EasyMock.expect(session.isExpired()).andReturn(false); - // session idle - EasyMock.expect(session.isIdle()).andReturn(true); - // idle onSessionIdle - session.onEvent(EventType.IDLE, this.reactor.getSelector()); - EasyMock.expectLastCall(); - - allKeys.add(key); - } - - - private void addInvalidKey(Set keySet) { - MockSelectionKey key = new MockSelectionKey(); - key.valid = false; - keySet.add(key); - } - - - private void addReadableKey(Set keySet, IMocksControl control, Selector selector) { - MockSelectionKey key = new MockSelectionKey(); - key.interestOps = SelectionKey.OP_READ; - NioSession session = control.createMock(NioSession.class); - session.onEvent(EventType.READABLE, selector); - EasyMock.expectLastCall(); - key.attach(session); - key.selector = selector; - keySet.add(key); - } - - - private void addWritableKey(Set keySet, IMocksControl control, Selector selector) { - MockSelectionKey key = new MockSelectionKey(); - key.interestOps = SelectionKey.OP_WRITE; - NioSession session = control.createMock(NioSession.class); - session.onEvent(EventType.WRITEABLE, selector); - EasyMock.expectLastCall(); - key.attach(session); - key.selector = selector; - keySet.add(key); - } - - - @After - public void tearDown() throws Exception { - if (this.selectorManager != null) { - this.selectorManager.stop(); - } - } + private Reactor reactor; + private SelectorManager selectorManager; + + @Before + public void setUp() throws Exception { + Configuration configuration = new Configuration(); + TCPController controller = new TCPController(configuration); + this.selectorManager = new SelectorManager(1, controller, + configuration); + this.selectorManager.start(); + this.reactor = this.selectorManager.getReactorByIndex(0); + controller.setSessionTimeout(1000); + controller.getConfiguration().setSessionIdleTimeout(1000); + } + + @Test + public void testRegisterOpenChannel() throws Exception { + MockSelectableChannel channel = new MockSelectableChannel(); + channel.selectionKey = new MockSelectionKey(); + this.reactor.registerChannel(channel, 1, "hello"); + Thread.sleep(Reactor.DEFAULT_WAIT * 3); + Assert.assertSame(this.reactor.getSelector(), channel.selector); + Assert.assertSame(this.reactor.getSelector(), + channel.selectionKey.selector); + Assert.assertEquals(1, channel.ops); + Assert.assertEquals("hello", channel.attch); + } + + @Test + public void testRegisterCloseChannel() throws Exception { + MockSelectableChannel channel = new MockSelectableChannel(); + channel.close(); + this.reactor.registerChannel(channel, 1, "hello"); + Thread.sleep(Reactor.DEFAULT_WAIT * 3); + Assert.assertNull(channel.selector); + Assert.assertEquals(0, channel.ops); + Assert.assertNull(channel.attch); + } + + @Test + public void testRegisterOpenSession() throws Exception { + IMocksControl control = EasyMock.createControl(); + NioSession session = control.createMock(NioSession.class); + session.onEvent(EventType.ENABLE_READ, this.reactor.getSelector()); + EasyMock.expectLastCall(); + EasyMock.expect(session.isClosed()).andReturn(false); + + control.replay(); + this.reactor.registerSession(session, EventType.ENABLE_READ); + Thread.sleep(Reactor.DEFAULT_WAIT * 3); + control.verify(); + } + + @Test + public void testRegisterCloseSession() throws Exception { + IMocksControl control = EasyMock.createControl(); + NioSession session = control.createMock(NioSession.class); + EasyMock.expect(session.isClosed()).andReturn(true); + control.replay(); + this.reactor.registerSession(session, EventType.ENABLE_READ); + Thread.sleep(Reactor.DEFAULT_WAIT * 3); + control.verify(); + } + + @Test + public void testDispatchEventAllValid() throws Exception { + IMocksControl control = EasyMock.createControl(); + Set keySet = new HashSet(); + addReadableKey(keySet, control, this.reactor.getSelector()); + addWritableKey(keySet, control, this.reactor.getSelector()); + control.replay(); + this.reactor.dispatchEvent(keySet); + Assert.assertEquals(0, keySet.size()); + control.verify(); + } + + @Test + public void testDispatchEventSomeInValid() throws Exception { + IMocksControl control = EasyMock.createControl(); + Set keySet = new HashSet(); + addInvalidKey(keySet); + addWritableKey(keySet, control, this.reactor.getSelector()); + control.replay(); + this.reactor.dispatchEvent(keySet); + Assert.assertEquals(0, keySet.size()); + control.verify(); + } + + @Test + public void testPostSelectOneTimeout() { + IMocksControl mocksControl = EasyMock.createControl(); + Set selectedKeys = new HashSet(); + Set allKeys = new HashSet(); + addTimeoutKey(mocksControl, allKeys); + allKeys.addAll(selectedKeys); + + mocksControl.replay(); + this.reactor.postSelect(selectedKeys, allKeys); + mocksControl.verify(); + + } + + private void addTimeoutKey(IMocksControl mocksControl, + Set allKeys) { + MockSelectionKey key = new MockSelectionKey(); + NioSession session = mocksControl.createMock(NioSession.class); + key.attach(session); + // �ж�session�Ƿ���ڣ�����Ϊ���� + EasyMock.expect(session.isExpired()).andReturn(true); + // ���ھͻ����onSessionExpired�����ر����� + // ͬʱ��expired��session�����ж�idle + session.onEvent(EventType.EXPIRED, this.reactor.getSelector()); + EasyMock.expectLastCall(); + session.close(); + EasyMock.expectLastCall(); + + allKeys.add(key); + } + + @Test + public void testPostSelectOneIdle() { + IMocksControl mocksControl = EasyMock.createControl(); + Set selectedKeys = new HashSet(); + Set allKeys = new HashSet(); + addIdleKey(mocksControl, allKeys); + allKeys.addAll(selectedKeys); + + mocksControl.replay(); + this.reactor.postSelect(selectedKeys, allKeys); + mocksControl.verify(); + + } + + @Test + public void testPostSelectMoreKeys() { + IMocksControl mocksControl = EasyMock.createControl(); + Set selectedKeys = new HashSet(); + Set allKeys = new HashSet(); + addIdleKey(mocksControl, allKeys); + addTimeoutKey(mocksControl, allKeys); + selectedKeys.add(new MockSelectionKey()); + selectedKeys.add(new MockSelectionKey()); + allKeys.addAll(selectedKeys); + + mocksControl.replay(); + this.reactor.postSelect(selectedKeys, allKeys); + mocksControl.verify(); + } + + private void addIdleKey(IMocksControl mocksControl, + Set allKeys) { + MockSelectionKey key = new MockSelectionKey(); + NioSession session = mocksControl.createMock(NioSession.class); + key.attach(session); + // session + EasyMock.expect(session.isExpired()).andReturn(false); + // session idle + EasyMock.expect(session.isIdle()).andReturn(true); + // idle onSessionIdle + session.onEvent(EventType.IDLE, this.reactor.getSelector()); + EasyMock.expectLastCall(); + + allKeys.add(key); + } + + private void addInvalidKey(Set keySet) { + MockSelectionKey key = new MockSelectionKey(); + key.valid = false; + keySet.add(key); + } + + private void addReadableKey(Set keySet, IMocksControl control, + Selector selector) { + MockSelectionKey key = new MockSelectionKey(); + key.interestOps = SelectionKey.OP_READ; + NioSession session = control.createMock(NioSession.class); + session.onEvent(EventType.READABLE, selector); + EasyMock.expectLastCall(); + key.attach(session); + key.selector = selector; + keySet.add(key); + } + + private void addWritableKey(Set keySet, IMocksControl control, + Selector selector) { + MockSelectionKey key = new MockSelectionKey(); + key.interestOps = SelectionKey.OP_WRITE; + NioSession session = control.createMock(NioSession.class); + session.onEvent(EventType.WRITEABLE, selector); + EasyMock.expectLastCall(); + key.attach(session); + key.selector = selector; + keySet.add(key); + } + + @After + public void tearDown() throws Exception { + if (this.selectorManager != null) { + this.selectorManager.stop(); + } + } } diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/SelectorManagerUnitTest.java b/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/SelectorManagerUnitTest.java index bb5dd9cd8..7f9fa213c 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/SelectorManagerUnitTest.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/nio/impl/SelectorManagerUnitTest.java @@ -15,7 +15,6 @@ import com.google.code.yanf4j.nio.impl.Reactor; import com.google.code.yanf4j.nio.impl.SelectorManager; - /** * * @@ -26,96 +25,94 @@ */ public class SelectorManagerUnitTest { - private SelectorManager selectorManager; - int selectorPoolSize = 3; - - - @Before - public void setUp() throws Exception { - Configuration configuration = new Configuration(); - TCPController controller = new TCPController(configuration); - this.selectorManager = new SelectorManager(this.selectorPoolSize, controller, configuration); - this.selectorManager.start(); - controller.setSessionTimeout(1000); - controller.getConfiguration().setSessionIdleTimeout(1000); - } - - - @Test - public void testNextReactor() { - long start = System.currentTimeMillis(); - for (int i = 0; i < 10000; i++) { - Reactor reactor = this.selectorManager.nextReactor(); - Assert.assertNotNull(reactor); - Assert.assertTrue(reactor.getReactorIndex() > 0); - } - System.out.println(System.currentTimeMillis() - start); - } - - - @Test - public void testRegisterOpenChannel() throws Exception { - MockSelectableChannel channel = new MockSelectableChannel(); - channel.selectionKey = new MockSelectionKey(); - Reactor reactor = this.selectorManager.registerChannel(channel, 1, "hello"); - Thread.sleep(Reactor.DEFAULT_WAIT * 3); - Assert.assertSame(reactor.getSelector(), channel.selector); - Assert.assertSame(reactor.getSelector(), channel.selectionKey.selector); - Assert.assertEquals(1, channel.ops); - Assert.assertEquals("hello", channel.attch); - } - - - @Test - public void testRegisterCloseChannel() throws Exception { - MockSelectableChannel channel = new MockSelectableChannel(); - channel.close(); - this.selectorManager.registerChannel(channel, 1, "hello"); - Thread.sleep(Reactor.DEFAULT_WAIT * 3); - Assert.assertNull(channel.selector); - Assert.assertEquals(0, channel.ops); - Assert.assertNull(channel.attch); - } - - - @Test - public void testRegisterOpenSession() throws Exception { - IMocksControl control = EasyMock.createControl(); - NioSession session = control.createMock(NioSession.class); - EasyMock.makeThreadSafe(session, true); - // next reactor index=2 - Reactor nextReactor = this.selectorManager.getReactorByIndex(2); - session.onEvent(EventType.ENABLE_READ, nextReactor.getSelector()); - EasyMock.expectLastCall(); - EasyMock.expect(session.isClosed()).andReturn(false).times(2); - EasyMock.expect(session.getAttribute(SelectorManager.REACTOR_ATTRIBUTE)).andReturn(null); - EasyMock.expect(session.setAttributeIfAbsent(SelectorManager.REACTOR_ATTRIBUTE, nextReactor)).andReturn(null); - - control.replay(); - this.selectorManager.registerSession(session, EventType.ENABLE_READ); - Thread.sleep(Reactor.DEFAULT_WAIT * 3); - control.verify(); - } - - - @Test - public void testRegisterCloseSession() throws Exception { - IMocksControl control = EasyMock.createControl(); - NioSession session = control.createMock(NioSession.class); - EasyMock.expect(session.isClosed()).andReturn(true); - control.replay(); - this.selectorManager.registerSession(session, EventType.ENABLE_READ); - Thread.sleep(Reactor.DEFAULT_WAIT * 3); - control.verify(); - } - - - @After - public void tearDown() throws Exception { - if (this.selectorManager != null) { - this.selectorManager.getController().stop(); - this.selectorManager.stop(); - } - } + private SelectorManager selectorManager; + int selectorPoolSize = 3; + + @Before + public void setUp() throws Exception { + Configuration configuration = new Configuration(); + TCPController controller = new TCPController(configuration); + this.selectorManager = new SelectorManager(this.selectorPoolSize, + controller, configuration); + this.selectorManager.start(); + controller.setSessionTimeout(1000); + controller.getConfiguration().setSessionIdleTimeout(1000); + } + + @Test + public void testNextReactor() { + long start = System.currentTimeMillis(); + for (int i = 0; i < 10000; i++) { + Reactor reactor = this.selectorManager.nextReactor(); + Assert.assertNotNull(reactor); + Assert.assertTrue(reactor.getReactorIndex() > 0); + } + System.out.println(System.currentTimeMillis() - start); + } + + @Test + public void testRegisterOpenChannel() throws Exception { + MockSelectableChannel channel = new MockSelectableChannel(); + channel.selectionKey = new MockSelectionKey(); + Reactor reactor = this.selectorManager.registerChannel(channel, 1, + "hello"); + Thread.sleep(Reactor.DEFAULT_WAIT * 3); + Assert.assertSame(reactor.getSelector(), channel.selector); + Assert.assertSame(reactor.getSelector(), channel.selectionKey.selector); + Assert.assertEquals(1, channel.ops); + Assert.assertEquals("hello", channel.attch); + } + + @Test + public void testRegisterCloseChannel() throws Exception { + MockSelectableChannel channel = new MockSelectableChannel(); + channel.close(); + this.selectorManager.registerChannel(channel, 1, "hello"); + Thread.sleep(Reactor.DEFAULT_WAIT * 3); + Assert.assertNull(channel.selector); + Assert.assertEquals(0, channel.ops); + Assert.assertNull(channel.attch); + } + + @Test + public void testRegisterOpenSession() throws Exception { + IMocksControl control = EasyMock.createControl(); + NioSession session = control.createMock(NioSession.class); + EasyMock.makeThreadSafe(session, true); + // next reactor index=2 + Reactor nextReactor = this.selectorManager.getReactorByIndex(2); + session.onEvent(EventType.ENABLE_READ, nextReactor.getSelector()); + EasyMock.expectLastCall(); + EasyMock.expect(session.isClosed()).andReturn(false).times(2); + EasyMock.expect(session.getAttribute(SelectorManager.REACTOR_ATTRIBUTE)) + .andReturn(null); + EasyMock.expect(session.setAttributeIfAbsent( + SelectorManager.REACTOR_ATTRIBUTE, nextReactor)) + .andReturn(null); + + control.replay(); + this.selectorManager.registerSession(session, EventType.ENABLE_READ); + Thread.sleep(Reactor.DEFAULT_WAIT * 3); + control.verify(); + } + + @Test + public void testRegisterCloseSession() throws Exception { + IMocksControl control = EasyMock.createControl(); + NioSession session = control.createMock(NioSession.class); + EasyMock.expect(session.isClosed()).andReturn(true); + control.replay(); + this.selectorManager.registerSession(session, EventType.ENABLE_READ); + Thread.sleep(Reactor.DEFAULT_WAIT * 3); + control.verify(); + } + + @After + public void tearDown() throws Exception { + if (this.selectorManager != null) { + this.selectorManager.getController().stop(); + this.selectorManager.stop(); + } + } } diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/statistics/SimpleStatisticsTest.java b/src/test/java/com/google/code/yanf4j/test/unittest/statistics/SimpleStatisticsTest.java index 21d13515a..eea3d3ae0 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/statistics/SimpleStatisticsTest.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/statistics/SimpleStatisticsTest.java @@ -56,7 +56,7 @@ public void testRead() throws Exception { assertEquals(5632, statistics.getRecvMessageTotalSize()); assertEquals(1877, statistics.getRecvMessageAverageSize()); assertEquals(3.0, statistics.getRecvMessageCountPerSecond(), 0.5); - + statistics.restart(); assertEquals(0, statistics.getRecvMessageCount()); assertEquals(0.0, statistics.getRecvMessageCountPerSecond()); diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/utils/ByteBufferMatcherTest.java b/src/test/java/com/google/code/yanf4j/test/unittest/utils/ByteBufferMatcherTest.java index 72ff8608b..139d7cfef 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/utils/ByteBufferMatcherTest.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/utils/ByteBufferMatcherTest.java @@ -15,43 +15,41 @@ public void testMatchFirst() { ByteBufferMatcher m = createByteBufferMatcher(hello); assertEquals(0, m.matchFirst(IoBuffer.wrap("hel;lo".getBytes()))); assertEquals(-1, m.matchFirst(IoBuffer.wrap("hel;l0".getBytes()))); - assertEquals(6, m - .matchFirst(IoBuffer.wrap("hello hel;lo".getBytes()))); - assertEquals(0, (m.matchFirst(IoBuffer - .wrap("hel;lo good ".getBytes())))); - assertEquals(7, m.matchFirst(IoBuffer.wrap("abcdefghel;lo good " - .getBytes()))); + assertEquals(6, m.matchFirst(IoBuffer.wrap("hello hel;lo".getBytes()))); + assertEquals(0, + (m.matchFirst(IoBuffer.wrap("hel;lo good ".getBytes())))); + assertEquals(7, + m.matchFirst(IoBuffer.wrap("abcdefghel;lo good ".getBytes()))); assertEquals(-1, m.matchFirst(IoBuffer.wrap("".getBytes()))); - assertEquals(6, m.matchFirst(IoBuffer.wrap( - "hello hel;lo".getBytes()).position(4))); - assertEquals(6, m.matchFirst(IoBuffer.wrap( - "hello hel;lo".getBytes()).position(6))); - assertEquals(-1, m.matchFirst(IoBuffer.wrap( - "hello hel;lo".getBytes()).limit(6))); + assertEquals(6, m.matchFirst( + IoBuffer.wrap("hello hel;lo".getBytes()).position(4))); + assertEquals(6, m.matchFirst( + IoBuffer.wrap("hello hel;lo".getBytes()).position(6))); + assertEquals(-1, m + .matchFirst(IoBuffer.wrap("hello hel;lo".getBytes()).limit(6))); assertEquals(-1, m.matchFirst(null)); assertEquals(-1, m.matchFirst(IoBuffer.allocate(0))); - - ByteBufferMatcher newline = new ShiftAndByteBufferMatcher(IoBuffer - .wrap("\r\n".getBytes())); + ByteBufferMatcher newline = new ShiftAndByteBufferMatcher( + IoBuffer.wrap("\r\n".getBytes())); String memcachedGet = "VALUE test 0 0 100\r\nhello\r\n"; - assertEquals(memcachedGet.indexOf("\r\n"), newline - .matchFirst(IoBuffer.wrap(memcachedGet.getBytes()))); - assertEquals(25, newline.matchFirst(IoBuffer.wrap( - memcachedGet.getBytes()).position(20))); + assertEquals(memcachedGet.indexOf("\r\n"), + newline.matchFirst(IoBuffer.wrap(memcachedGet.getBytes()))); + assertEquals(25, newline.matchFirst( + IoBuffer.wrap(memcachedGet.getBytes()).position(20))); } public abstract ByteBufferMatcher createByteBufferMatcher(String hello); public void testMatchAll() { String memcachedGet = "VALUE test 0 0 100\r\nhello\r\n\rtestgood\r\nh\rfasdfasd\n\rdfasdfad\r\n\r\n"; - ByteBufferMatcher newline = new ShiftOrByteBufferMatcher(IoBuffer - .wrap("\r\n".getBytes())); - List list = newline.matchAll(IoBuffer.wrap(memcachedGet - .getBytes())); + ByteBufferMatcher newline = new ShiftOrByteBufferMatcher( + IoBuffer.wrap("\r\n".getBytes())); + List list = newline + .matchAll(IoBuffer.wrap(memcachedGet.getBytes())); for (int i : list) { System.out.println(i); } diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/utils/ByteBufferUtilsTest.java b/src/test/java/com/google/code/yanf4j/test/unittest/utils/ByteBufferUtilsTest.java index 5399a8db9..e3f190e77 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/utils/ByteBufferUtilsTest.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/utils/ByteBufferUtilsTest.java @@ -13,8 +13,8 @@ public void testIncreaseBlankBufferCapatity() { ByteBuffer buffer = ByteBuffer.allocate(1024); buffer = ByteBufferUtils.increaseBufferCapatity(buffer); - assertEquals(1024 + Configuration.DEFAULT_INCREASE_BUFF_SIZE, buffer - .capacity()); + assertEquals(1024 + Configuration.DEFAULT_INCREASE_BUFF_SIZE, + buffer.capacity()); buffer = ByteBufferUtils.increaseBufferCapatity(buffer); assertEquals(1024 + 2 * Configuration.DEFAULT_INCREASE_BUFF_SIZE, buffer.capacity()); @@ -25,8 +25,8 @@ public void testIncreaseNotBlankBufferCapatity() { ByteBuffer buffer = ByteBuffer.allocate(1024); buffer.putInt(100); buffer = ByteBufferUtils.increaseBufferCapatity(buffer); - assertEquals(1024 + Configuration.DEFAULT_INCREASE_BUFF_SIZE, buffer - .capacity()); + assertEquals(1024 + Configuration.DEFAULT_INCREASE_BUFF_SIZE, + buffer.capacity()); assertEquals(4, buffer.position()); assertEquals(1024 + Configuration.DEFAULT_INCREASE_BUFF_SIZE - 4, buffer.remaining()); @@ -34,8 +34,9 @@ public void testIncreaseNotBlankBufferCapatity() { assertEquals(12, buffer.position()); buffer = ByteBufferUtils.increaseBufferCapatity(buffer); assertEquals(12, buffer.position()); - assertEquals(1024 + 2 * Configuration.DEFAULT_INCREASE_BUFF_SIZE - 4 - - 8, buffer.remaining()); + assertEquals( + 1024 + 2 * Configuration.DEFAULT_INCREASE_BUFF_SIZE - 4 - 8, + buffer.remaining()); } @@ -118,18 +119,18 @@ public void testIndexOf() { ByteBuffer buffer = ByteBuffer.wrap(words.getBytes()); String world = "world"; - assertEquals(6, ByteBufferUtils.indexOf(buffer, ByteBuffer.wrap(world - .getBytes()))); - assertEquals(0, ByteBufferUtils.indexOf(buffer, ByteBuffer.wrap("hello" - .getBytes()))); + assertEquals(6, ByteBufferUtils.indexOf(buffer, + ByteBuffer.wrap(world.getBytes()))); + assertEquals(0, ByteBufferUtils.indexOf(buffer, + ByteBuffer.wrap("hello".getBytes()))); long start = System.currentTimeMillis(); for (int i = 0; i < 10000; i++) { - assertEquals(17, ByteBufferUtils.indexOf(buffer, ByteBuffer - .wrap("hello".getBytes()), 6)); + assertEquals(17, ByteBufferUtils.indexOf(buffer, + ByteBuffer.wrap("hello".getBytes()), 6)); } System.out.println(System.currentTimeMillis() - start); - assertEquals(-1, ByteBufferUtils.indexOf(buffer, ByteBuffer.wrap("test" - .getBytes()))); + assertEquals(-1, ByteBufferUtils.indexOf(buffer, + ByteBuffer.wrap("test".getBytes()))); assertEquals(-1, ByteBufferUtils.indexOf(buffer, (ByteBuffer) null)); assertEquals(-1, ByteBufferUtils.indexOf(null, buffer)); } @@ -138,10 +139,11 @@ public void testGather() { ByteBuffer buffer1 = ByteBuffer.wrap("hello".getBytes()); ByteBuffer buffer2 = ByteBuffer.wrap(" dennis".getBytes()); - ByteBuffer gather=ByteBufferUtils.gather(new ByteBuffer[] { buffer1, buffer2 }); - - assertEquals("hello dennis",new String(gather.array())); - + ByteBuffer gather = ByteBufferUtils + .gather(new ByteBuffer[]{buffer1, buffer2}); + + assertEquals("hello dennis", new String(gather.array())); + assertNull(ByteBufferUtils.gather(null)); assertNull(ByteBufferUtils.gather(new ByteBuffer[]{})); } diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/utils/DispatcherFactoryUnitTest.java b/src/test/java/com/google/code/yanf4j/test/unittest/utils/DispatcherFactoryUnitTest.java index b99a2a867..724bdf424 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/utils/DispatcherFactoryUnitTest.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/utils/DispatcherFactoryUnitTest.java @@ -15,7 +15,7 @@ public class DispatcherFactoryUnitTest { @Test public void testNewDispatcher() throws Exception { Dispatcher dispatcher = DispatcherFactory.newDispatcher(1, - new ThreadPoolExecutor.AbortPolicy(),"test"); + new ThreadPoolExecutor.AbortPolicy(), "test"); Assert.assertNotNull(dispatcher); final CountDownLatch latch = new CountDownLatch(1); final AtomicInteger count = new AtomicInteger(); @@ -29,9 +29,9 @@ public void run() { Assert.assertEquals(1, count.get()); Assert.assertNull(DispatcherFactory.newDispatcher(0, - new ThreadPoolExecutor.AbortPolicy(),"test")); + new ThreadPoolExecutor.AbortPolicy(), "test")); Assert.assertNull(DispatcherFactory.newDispatcher(-1, - new ThreadPoolExecutor.AbortPolicy(),"test")); + new ThreadPoolExecutor.AbortPolicy(), "test")); dispatcher.stop(); try { dispatcher.dispatch(new Runnable() { diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/utils/ShiftAndByteBufferMatcherTest.java b/src/test/java/com/google/code/yanf4j/test/unittest/utils/ShiftAndByteBufferMatcherTest.java index a1d2acf7a..ac7a2d535 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/utils/ShiftAndByteBufferMatcherTest.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/utils/ShiftAndByteBufferMatcherTest.java @@ -4,11 +4,11 @@ import com.google.code.yanf4j.util.ByteBufferMatcher; import com.google.code.yanf4j.util.ShiftAndByteBufferMatcher; -public class ShiftAndByteBufferMatcherTest extends ByteBufferMatcherTest { +public class ShiftAndByteBufferMatcherTest extends ByteBufferMatcherTest { @Override public ByteBufferMatcher createByteBufferMatcher(String hello) { - ByteBufferMatcher m = new ShiftAndByteBufferMatcher(IoBuffer.wrap(hello - .getBytes())); + ByteBufferMatcher m = new ShiftAndByteBufferMatcher( + IoBuffer.wrap(hello.getBytes())); return m; } } diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/utils/ShiftOrByteBufferMatcherTest.java b/src/test/java/com/google/code/yanf4j/test/unittest/utils/ShiftOrByteBufferMatcherTest.java index a966c696e..cc71ed820 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/utils/ShiftOrByteBufferMatcherTest.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/utils/ShiftOrByteBufferMatcherTest.java @@ -4,11 +4,11 @@ import com.google.code.yanf4j.util.ByteBufferMatcher; import com.google.code.yanf4j.util.ShiftOrByteBufferMatcher; -public class ShiftOrByteBufferMatcherTest extends ByteBufferMatcherTest { +public class ShiftOrByteBufferMatcherTest extends ByteBufferMatcherTest { @Override public ByteBufferMatcher createByteBufferMatcher(String hello) { - ByteBufferMatcher m = new ShiftOrByteBufferMatcher(IoBuffer.wrap(hello - .getBytes())); + ByteBufferMatcher m = new ShiftOrByteBufferMatcher( + IoBuffer.wrap(hello.getBytes())); return m; } } diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/utils/SystemUtilsUniTest.java b/src/test/java/com/google/code/yanf4j/test/unittest/utils/SystemUtilsUniTest.java index 1208c1fc7..ff11fa85f 100644 --- a/src/test/java/com/google/code/yanf4j/test/unittest/utils/SystemUtilsUniTest.java +++ b/src/test/java/com/google/code/yanf4j/test/unittest/utils/SystemUtilsUniTest.java @@ -18,8 +18,7 @@ public void testOpenSelector() throws IOException { assertTrue(pollClassName.equals("sun.nio.ch.EPollSelectorProvider") || pollClassName.equals("sun.nio.ch.PollSelectorProvider")); } - Selector selector2 = SystemUtils.openSelector(); - ; + Selector selector2 = SystemUtils.openSelector();; assertNotSame(selector, selector2); selector.close(); selector2.close(); diff --git a/src/test/java/net/rubyeye/xmemcached/example/BinaryProtocolExample.java b/src/test/java/net/rubyeye/xmemcached/example/BinaryProtocolExample.java index 350fb9d64..293e0a19c 100644 --- a/src/test/java/net/rubyeye/xmemcached/example/BinaryProtocolExample.java +++ b/src/test/java/net/rubyeye/xmemcached/example/BinaryProtocolExample.java @@ -20,8 +20,9 @@ */ public class BinaryProtocolExample { - private static final Logger log = LoggerFactory.getLogger(BinaryProtocolExample.class); - + private static final Logger log = LoggerFactory + .getLogger(BinaryProtocolExample.class); + public static void main(String[] args) { if (args.length < 1) { System.err.println("Useage:java BinaryProtocolExample [servers]"); diff --git a/src/test/java/net/rubyeye/xmemcached/example/CASExample.java b/src/test/java/net/rubyeye/xmemcached/example/CASExample.java index ebb75e4e0..23ee29634 100644 --- a/src/test/java/net/rubyeye/xmemcached/example/CASExample.java +++ b/src/test/java/net/rubyeye/xmemcached/example/CASExample.java @@ -29,9 +29,8 @@ */ class CASThread extends Thread { - private static final Logger log = LoggerFactory.getLogger(CASThread.class); - + /** * Increase Operation * @@ -75,14 +74,14 @@ public void run() { public class CASExample { public static void main(String[] args) throws Exception { - //125489 + // 125489 if (args.length < 2) { System.err.println("Usage:java CASTest [threadNum] [server]"); System.exit(1); } int NUM = Integer.parseInt(args[0]); - MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil - .getAddresses(args[1])); + MemcachedClientBuilder builder = new XMemcachedClientBuilder( + AddrUtil.getAddresses(args[1])); // use binary protocol builder.setCommandFactory(new BinaryCommandFactory()); MemcachedClient mc = builder.build(); @@ -96,8 +95,8 @@ public static void main(String[] args) throws Exception { } cdl.await(); - System.out.println("test cas,timed:" - + (System.currentTimeMillis() - start)); + System.out.println( + "test cas,timed:" + (System.currentTimeMillis() - start)); // print result,must equals to NUM System.out.println("result=" + mc.get("a")); mc.shutdown(); diff --git a/src/test/java/net/rubyeye/xmemcached/example/MemcachedStateListenerExample.java b/src/test/java/net/rubyeye/xmemcached/example/MemcachedStateListenerExample.java index 552d6dcc2..a190e651f 100644 --- a/src/test/java/net/rubyeye/xmemcached/example/MemcachedStateListenerExample.java +++ b/src/test/java/net/rubyeye/xmemcached/example/MemcachedStateListenerExample.java @@ -26,7 +26,8 @@ public void onDisconnected(MemcachedClient memcachedClient, } - public void onException(MemcachedClient memcachedClient, Throwable throwable) { + public void onException(MemcachedClient memcachedClient, + Throwable throwable) { log.error(throwable.getMessage(), throwable); } @@ -45,12 +46,13 @@ public void onStarted(MemcachedClient memcachedClient) { public class MemcachedStateListenerExample { - private static final Logger log = LoggerFactory.getLogger(MemcachedStateListenerExample.class); - + private static final Logger log = LoggerFactory + .getLogger(MemcachedStateListenerExample.class); + public static void main(String[] args) { if (args.length < 1) { - System.err - .println("Useage:java MemcachedStateListenerExample [servers]"); + System.err.println( + "Useage:java MemcachedStateListenerExample [servers]"); System.exit(1); } MemcachedClient memcachedClient = getMemcachedClient(args[0]); diff --git a/src/test/java/net/rubyeye/xmemcached/example/SASLExample.java b/src/test/java/net/rubyeye/xmemcached/example/SASLExample.java index 0d9e044fc..e56d5ee35 100644 --- a/src/test/java/net/rubyeye/xmemcached/example/SASLExample.java +++ b/src/test/java/net/rubyeye/xmemcached/example/SASLExample.java @@ -27,12 +27,13 @@ */ public class SASLExample { - private static final Logger log = LoggerFactory.getLogger(SASLExample.class); + private static final Logger log = LoggerFactory + .getLogger(SASLExample.class); public static void main(String[] args) { if (args.length < 3) { - System.err - .println("Useage:java SASLExample servers username password"); + System.err.println( + "Useage:java SASLExample servers username password"); System.exit(1); } MemcachedClient memcachedClient = getMemcachedClient(args[0], args[1], @@ -72,8 +73,8 @@ public static MemcachedClient getMemcachedClient(String servers, try { MemcachedClientBuilder builder = new XMemcachedClientBuilder( AddrUtil.getAddresses(servers)); - builder.addAuthInfo(AddrUtil.getOneAddress(servers), AuthInfo - .typical(username, password)); + builder.addAuthInfo(AddrUtil.getOneAddress(servers), + AuthInfo.typical(username, password)); // Must use binary protocol builder.setCommandFactory(new BinaryCommandFactory()); return builder.build(); diff --git a/src/test/java/net/rubyeye/xmemcached/example/SimpleExample.java b/src/test/java/net/rubyeye/xmemcached/example/SimpleExample.java index 643d1b0a2..29e66e6d1 100644 --- a/src/test/java/net/rubyeye/xmemcached/example/SimpleExample.java +++ b/src/test/java/net/rubyeye/xmemcached/example/SimpleExample.java @@ -20,7 +20,8 @@ */ public class SimpleExample { - private static final Logger log = LoggerFactory.getLogger(SimpleExample.class); + private static final Logger log = LoggerFactory + .getLogger(SimpleExample.class); public static void main(String[] args) { if (args.length < 1) { @@ -50,8 +51,8 @@ public static void main(String[] args) { System.out.println("Iterate all keys..."); // iterate all keys - KeyIterator it = memcachedClient.getKeyIterator(AddrUtil - .getOneAddress(args[0])); + KeyIterator it = memcachedClient + .getKeyIterator(AddrUtil.getOneAddress(args[0])); while (it.hasNext()) { System.out.println(it.next()); } diff --git a/src/test/java/net/rubyeye/xmemcached/example/SpringExample.java b/src/test/java/net/rubyeye/xmemcached/example/SpringExample.java index e443e0ff8..0fef033cc 100644 --- a/src/test/java/net/rubyeye/xmemcached/example/SpringExample.java +++ b/src/test/java/net/rubyeye/xmemcached/example/SpringExample.java @@ -5,14 +5,14 @@ import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringExample { - public static void main(String[] args) throws Exception{ + public static void main(String[] args) throws Exception { ApplicationContext ctx = new ClassPathXmlApplicationContext( "sampleApplicationContext.xml"); MemcachedClient client1 = (MemcachedClient) ctx .getBean("memcachedClient1"); MemcachedClient client2 = (MemcachedClient) ctx - .getBean("memcachedClient2"); + .getBean("memcachedClient2"); test(client1); test(client2); client1.shutdown(); diff --git a/src/test/java/net/rubyeye/xmemcached/helper/AbstractChecker.java b/src/test/java/net/rubyeye/xmemcached/helper/AbstractChecker.java index 53d73c8c0..114818aec 100644 --- a/src/test/java/net/rubyeye/xmemcached/helper/AbstractChecker.java +++ b/src/test/java/net/rubyeye/xmemcached/helper/AbstractChecker.java @@ -5,10 +5,10 @@ public abstract class AbstractChecker implements ExceptionChecker { - private static final double EPSILON = 0.00000001; + private static final double EPSILON = 0.00000001; public void call() throws Exception { // TODO Auto-generated method stub - + } /** @@ -110,7 +110,8 @@ static public void assertEquals(String message, double expected, // the following test fails if (Double.isInfinite(expected)) { if (!(Math.abs(expected - actual) <= EPSILON)) - failNotEquals(message, new Double(expected), new Double(actual)); + failNotEquals(message, new Double(expected), + new Double(actual)); } else if (!(Math.abs(expected - actual) <= delta)) // Because // comparison with // NaN always @@ -122,7 +123,8 @@ static public void assertEquals(String message, double expected, * Asserts that two doubles are equal concerning a delta. If the expected * value is infinity then the delta value is ignored. */ - static public void assertEquals(double expected, double actual, double delta) { + static public void assertEquals(double expected, double actual, + double delta) { assertEquals(null, expected, actual, delta); } @@ -155,7 +157,8 @@ static public void assertEquals(float expected, float actual, float delta) { * Asserts that two longs are equal. If they are not an AssertionFailedError * is thrown with the given message. */ - static public void assertEquals(String message, long expected, long actual) { + static public void assertEquals(String message, long expected, + long actual) { assertEquals(message, new Long(expected), new Long(actual)); } @@ -186,7 +189,8 @@ static public void assertEquals(boolean expected, boolean actual) { * Asserts that two bytes are equal. If they are not an AssertionFailedError * is thrown with the given message. */ - static public void assertEquals(String message, byte expected, byte actual) { + static public void assertEquals(String message, byte expected, + byte actual) { assertEquals(message, new Byte(expected), new Byte(actual)); } @@ -201,7 +205,8 @@ static public void assertEquals(byte expected, byte actual) { * Asserts that two chars are equal. If they are not an AssertionFailedError * is thrown with the given message. */ - static public void assertEquals(String message, char expected, char actual) { + static public void assertEquals(String message, char expected, + char actual) { assertEquals(message, new Character(expected), new Character(actual)); } @@ -216,7 +221,8 @@ static public void assertEquals(char expected, char actual) { * Asserts that two shorts are equal. If they are not an * AssertionFailedError is thrown with the given message. */ - static public void assertEquals(String message, short expected, short actual) { + static public void assertEquals(String message, short expected, + short actual) { assertEquals(message, new Short(expected), new Short(actual)); } @@ -276,7 +282,8 @@ static public void assertNull(String message, Object object) { * Asserts that two objects refer to the same object. If they are not an * AssertionFailedError is thrown with the given message. */ - static public void assertSame(String message, Object expected, Object actual) { + static public void assertSame(String message, Object expected, + Object actual) { if (expected == actual) return; failNotSame(message, expected, actual); diff --git a/src/test/java/net/rubyeye/xmemcached/helper/InValidKeyChecker.java b/src/test/java/net/rubyeye/xmemcached/helper/InValidKeyChecker.java index 62365ed75..c7b8b2a22 100644 --- a/src/test/java/net/rubyeye/xmemcached/helper/InValidKeyChecker.java +++ b/src/test/java/net/rubyeye/xmemcached/helper/InValidKeyChecker.java @@ -7,8 +7,8 @@ public void check() throws Exception { call(); fail(); } catch (IllegalArgumentException e) { - assertTrue(e.getMessage().startsWith( - "Key contains invalid characters")); + assertTrue(e.getMessage() + .startsWith("Key contains invalid characters")); } } diff --git a/src/test/java/net/rubyeye/xmemcached/helper/MockTranscoder.java b/src/test/java/net/rubyeye/xmemcached/helper/MockTranscoder.java index 1a2577727..d62eba843 100644 --- a/src/test/java/net/rubyeye/xmemcached/helper/MockTranscoder.java +++ b/src/test/java/net/rubyeye/xmemcached/helper/MockTranscoder.java @@ -9,11 +9,9 @@ public class MockTranscoder implements Transcoder { private volatile int count; private SerializingTranscoder serializingTranscoder = new SerializingTranscoder(); - - public void setCompressionMode(CompressionMode compressMode) { this.serializingTranscoder.setCompressionMode(compressMode); - + } public int getCount() { diff --git a/src/test/java/net/rubyeye/xmemcached/helper/TooLongKeyChecker.java b/src/test/java/net/rubyeye/xmemcached/helper/TooLongKeyChecker.java index e89640c87..c11380d81 100644 --- a/src/test/java/net/rubyeye/xmemcached/helper/TooLongKeyChecker.java +++ b/src/test/java/net/rubyeye/xmemcached/helper/TooLongKeyChecker.java @@ -5,23 +5,20 @@ public class TooLongKeyChecker extends AbstractChecker { private MemcachedClient client; - public TooLongKeyChecker(MemcachedClient client) { super(); this.client = client; } - public void check() throws Exception { try { call(); fail(); } catch (IllegalArgumentException e) { - assertEquals( - "Key is too long (maxlen = " - + (this.client.getProtocol() == Protocol.Text ? 250 - : 250) + ")", e.getMessage()); + assertEquals("Key is too long (maxlen = " + + (this.client.getProtocol() == Protocol.Text ? 250 : 250) + + ")", e.getMessage()); } } diff --git a/src/test/java/net/rubyeye/xmemcached/helper/TranscoderChecker.java b/src/test/java/net/rubyeye/xmemcached/helper/TranscoderChecker.java index 2b579613a..dfa23c891 100644 --- a/src/test/java/net/rubyeye/xmemcached/helper/TranscoderChecker.java +++ b/src/test/java/net/rubyeye/xmemcached/helper/TranscoderChecker.java @@ -4,10 +4,10 @@ public class TranscoderChecker extends AbstractChecker { private MockTranscoder mockTranscoder; private int expectCount; - public TranscoderChecker(MockTranscoder mockTranscoder,int expectedCount) { + public TranscoderChecker(MockTranscoder mockTranscoder, int expectedCount) { super(); this.mockTranscoder = mockTranscoder; - this.expectCount=expectedCount; + this.expectCount = expectedCount; } public void check() throws Exception { diff --git a/src/test/java/net/rubyeye/xmemcached/pressure/MemcachedClientPressureTest.java b/src/test/java/net/rubyeye/xmemcached/pressure/MemcachedClientPressureTest.java index cf74b57bd..e84f7ece6 100644 --- a/src/test/java/net/rubyeye/xmemcached/pressure/MemcachedClientPressureTest.java +++ b/src/test/java/net/rubyeye/xmemcached/pressure/MemcachedClientPressureTest.java @@ -100,7 +100,7 @@ public static void main(String[] args) throws Exception { final AtomicInteger success = new AtomicInteger(); MemcachedClientBuilder builder = new XMemcachedClientBuilder( AddrUtil.getAddresses(servers)); - //builder.setCommandFactory(new BinaryCommandFactory()); + // builder.setCommandFactory(new BinaryCommandFactory()); MemcachedClient client = builder.build(); ClockWatch watch = new ClockWatch(); CyclicBarrier barrier = new CyclicBarrier(threads + 1, watch); diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/AWSElasticCacheClientIT.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/AWSElasticCacheClientIT.java index c1e966776..b4b3d39c7 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/AWSElasticCacheClientIT.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/AWSElasticCacheClientIT.java @@ -58,8 +58,8 @@ public void onMessageReceived(Session session, Object message) { public void setUp() throws Exception { Properties properties = ResourcesUtils .getResourceAsProperties("test.properties"); - List addresses = AddrUtil.getAddresses(properties - .getProperty("test.memcached.servers")); + List addresses = AddrUtil + .getAddresses(properties.getProperty("test.memcached.servers")); StringBuffer sb = new StringBuffer(); boolean wasFirst = true; for (InetSocketAddress addr : addresses) { diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/BinaryMemcachedClientIT.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/BinaryMemcachedClientIT.java index 6fac06c68..e605e01b5 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/BinaryMemcachedClientIT.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/BinaryMemcachedClientIT.java @@ -27,9 +27,9 @@ public class BinaryMemcachedClientIT extends XMemcachedClientIT { @Override public MemcachedClientBuilder createBuilder() throws Exception { - MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil - .getAddresses(this.properties - .getProperty("test.memcached.servers"))); + MemcachedClientBuilder builder = new XMemcachedClientBuilder( + AddrUtil.getAddresses( + this.properties.getProperty("test.memcached.servers"))); builder.setCommandFactory(new BinaryCommandFactory()); ByteUtils.testing = true; return builder; @@ -37,9 +37,8 @@ public MemcachedClientBuilder createBuilder() throws Exception { @Override public MemcachedClientBuilder createWeightedBuilder() throws Exception { - List addressList = AddrUtil - .getAddresses(this.properties - .getProperty("test.memcached.servers")); + List addressList = AddrUtil.getAddresses( + this.properties.getProperty("test.memcached.servers")); int[] weights = new int[addressList.size()]; for (int i = 0; i < weights.length; i++) { weights[i] = i + 1; @@ -58,16 +57,16 @@ public MemcachedClientBuilder createWeightedBuilder() throws Exception { public void testTouch() throws Exception { if (this.isMemcached1_6()) { assertNull(this.memcachedClient.get("name")); - this.memcachedClient.set("name", 1, "dennis", new StringTranscoder(), - 1000); - assertEquals("dennis", this.memcachedClient.get("name", - new StringTranscoder())); + this.memcachedClient.set("name", 1, "dennis", + new StringTranscoder(), 1000); + assertEquals("dennis", + this.memcachedClient.get("name", new StringTranscoder())); // touch expiration to three seconds System.out.println(this.memcachedClient.touch("name", 3)); Thread.sleep(2000); - assertEquals("dennis", this.memcachedClient.get("name", - new StringTranscoder())); + assertEquals("dennis", + this.memcachedClient.get("name", new StringTranscoder())); Thread.sleep(1500); assertNull(this.memcachedClient.get("name")); } @@ -85,13 +84,13 @@ public void testTouchNotExists() throws Exception { public void testGetAndTouch_OneKey() throws Exception { if (this.isMemcached1_6()) { assertNull(this.memcachedClient.get("name")); - this.memcachedClient.set("name", 1, "dennis", new StringTranscoder(), - 1000); + this.memcachedClient.set("name", 1, "dennis", + new StringTranscoder(), 1000); assertEquals("dennis", this.memcachedClient.getAndTouch("name", 3)); Thread.sleep(2000); - assertEquals("dennis", this.memcachedClient.get("name", - new StringTranscoder())); + assertEquals("dennis", + this.memcachedClient.get("name", new StringTranscoder())); Thread.sleep(1500); assertNull(this.memcachedClient.get("name")); } @@ -119,7 +118,7 @@ public void testGetAndTouch_NotExistsKey() throws Exception { } @Test - public void testDeleteWithCAS()throws Exception{ + public void testDeleteWithCAS() throws Exception { this.memcachedClient.set("a", 0, 1); GetsResponse gets = this.memcachedClient.gets("a"); this.memcachedClient.set("a", 0, 2); diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/ConnectionPoolMemcachedClientIT.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/ConnectionPoolMemcachedClientIT.java index ec795e006..303481004 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/ConnectionPoolMemcachedClientIT.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/ConnectionPoolMemcachedClientIT.java @@ -21,9 +21,9 @@ public class ConnectionPoolMemcachedClientIT extends XMemcachedClientIT { @Override public MemcachedClientBuilder createBuilder() throws Exception { - MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil - .getAddresses(properties - .getProperty("test.memcached.servers"))); + MemcachedClientBuilder builder = new XMemcachedClientBuilder( + AddrUtil.getAddresses( + properties.getProperty("test.memcached.servers"))); builder.setConnectionPoolSize(CONNECTION_POOL_SIZE); return builder; } @@ -110,7 +110,7 @@ public void testHealSession() throws Exception { client.shutdown(); } - + public void testDisableHealSession() throws Exception { MockServer server = new MockServer(); server.start(); @@ -118,7 +118,7 @@ public void testDisableHealSession() throws Exception { XMemcachedClient client = new XMemcachedClient(); client.setConnectionPoolSize(5); client.setEnableHeartBeat(false); - //disable heal session. + // disable heal session. client.setEnableHealSession(false); client.addServer(serverAddress); synchronized (this) { @@ -140,7 +140,7 @@ public void testDisableHealSession() throws Exception { server = new MockServer(); server.start(); Thread.sleep(30000); - //Still empty. + // Still empty. assertEquals(0, client.getAvaliableServers().size()); assertEquals(0, client.getConnectionSizeBySocketAddress(serverAddress)); @@ -152,8 +152,7 @@ public void testDisableHealSession() throws Exception { @Override public MemcachedClientBuilder createWeightedBuilder() throws Exception { List addressList = AddrUtil - .getAddresses(properties - .getProperty("test.memcached.servers")); + .getAddresses(properties.getProperty("test.memcached.servers")); int[] weights = new int[addressList.size()]; for (int i = 0; i < weights.length; i++) { weights[i] = i + 1; diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/ConsistentHashMemcachedClientIT.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/ConsistentHashMemcachedClientIT.java index adbef2830..8f6f68ade 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/ConsistentHashMemcachedClientIT.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/ConsistentHashMemcachedClientIT.java @@ -8,11 +8,14 @@ import net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator; import net.rubyeye.xmemcached.utils.AddrUtil; -public class ConsistentHashMemcachedClientIT extends StandardHashMemcachedClientIT { +public class ConsistentHashMemcachedClientIT + extends + StandardHashMemcachedClientIT { @Override public MemcachedClientBuilder createBuilder() throws Exception { - MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil - .getAddresses(properties.getProperty("test.memcached.servers"))); + MemcachedClientBuilder builder = new XMemcachedClientBuilder( + AddrUtil.getAddresses( + properties.getProperty("test.memcached.servers"))); builder.setSessionLocator(new KetamaMemcachedSessionLocator()); return builder; @@ -20,8 +23,8 @@ public MemcachedClientBuilder createBuilder() throws Exception { @Override public MemcachedClientBuilder createWeightedBuilder() throws Exception { - List addressList = AddrUtil.getAddresses(properties - .getProperty("test.memcached.servers")); + List addressList = AddrUtil + .getAddresses(properties.getProperty("test.memcached.servers")); int[] weights = new int[addressList.size()]; for (int i = 0; i < weights.length; i++) { weights[i] = i + 1; diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/FailureModeUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/FailureModeUnitTest.java index 98443f076..0823d6b5c 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/FailureModeUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/FailureModeUnitTest.java @@ -65,8 +65,8 @@ public void testFailureMode_HasStandbyNode() throws Exception { memServer2.setCodecFactory(new TextLineCodecFactory()); memServer2.bind(new InetSocketAddress(4798)); - MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil - .getAddressMap("localhost:4799,localhost:4798")); + MemcachedClientBuilder builder = new XMemcachedClientBuilder( + AddrUtil.getAddressMap("localhost:4799,localhost:4798")); // It must be in failure mode builder.setFailureMode(true); MemcachedClient client = builder.build(); @@ -103,8 +103,8 @@ public void testFailureMode_OneServerDownOnStartup() throws Exception { memServer2.setCodecFactory(new TextLineCodecFactory()); memServer2.bind(new InetSocketAddress(4798)); - MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil - .getAddressMap("localhost:4799 localhost:4798")); + MemcachedClientBuilder builder = new XMemcachedClientBuilder( + AddrUtil.getAddressMap("localhost:4799 localhost:4798")); // It must be in failure mode builder.setFailureMode(true); MemcachedClient client = builder.build(); @@ -118,18 +118,24 @@ public void testFailureMode_OneServerDownOnStartup() throws Exception { assertEquals("response from server1", client.get("b")); fail(); } catch (MemcachedException e) { - assertEquals("Session(127.0.0.1:4799) has been closed", e - .getMessage()); + assertEquals("Session(127.0.0.1:4799) has been closed", + e.getMessage()); } - assertEquals(1, client.getConnector().getSessionByAddress( - AddrUtil.getOneAddress("localhost:4799")).size()); + assertEquals(1, + client.getConnector() + .getSessionByAddress( + AddrUtil.getOneAddress("localhost:4799")) + .size()); memServer1 = new TCPController(); memServer1.setHandler(new MockHandler("response from server1")); memServer1.setCodecFactory(new TextLineCodecFactory()); memServer1.bind(new InetSocketAddress(4799)); Thread.sleep(5000); - assertEquals(1, client.getConnector().getSessionByAddress( - AddrUtil.getOneAddress("localhost:4799")).size()); + assertEquals(1, + client.getConnector() + .getSessionByAddress( + AddrUtil.getOneAddress("localhost:4799")) + .size()); assertEquals("response from server2", client.get("a")); assertEquals("response from server1", client.get("b")); } finally { @@ -153,8 +159,8 @@ public void testFailureMode_StandbyNodeDown_Recover() throws Exception { memServer2.setCodecFactory(new TextLineCodecFactory()); memServer2.bind(new InetSocketAddress(4798)); - MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil - .getAddressMap("localhost:4799,localhost:4798")); + MemcachedClientBuilder builder = new XMemcachedClientBuilder( + AddrUtil.getAddressMap("localhost:4799,localhost:4798")); // It must be in failure mode builder.setFailureMode(true); MemcachedClient client = builder.build(); @@ -173,8 +179,8 @@ public void testFailureMode_StandbyNodeDown_Recover() throws Exception { client.get("a"); fail(); } catch (MemcachedException e) { - assertEquals("Session(127.0.0.1:4799) has been closed", e - .getMessage()); + assertEquals("Session(127.0.0.1:4799) has been closed", + e.getMessage()); // e.printStackTrace(); } // restart server2 @@ -208,8 +214,8 @@ public void testFailureMode_NoStandbyNode() throws Exception { memServer1.setCodecFactory(new TextLineCodecFactory()); memServer1.bind(new InetSocketAddress(4799)); - MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil - .getAddressMap("localhost:4799")); + MemcachedClientBuilder builder = new XMemcachedClientBuilder( + AddrUtil.getAddressMap("localhost:4799")); builder.setFailureMode(true); MemcachedClient client = builder.build(); @@ -225,8 +231,8 @@ public void testFailureMode_NoStandbyNode() throws Exception { client.get("a"); fail(); } catch (MemcachedException e) { - assertEquals("Session(127.0.0.1:4799) has been closed", e - .getMessage()); + assertEquals("Session(127.0.0.1:4799) has been closed", + e.getMessage()); assertTrue(true); } } finally { @@ -248,8 +254,8 @@ public void testNotFailureMode_HasStandbyNode() throws Exception { memServer2.setCodecFactory(new TextLineCodecFactory()); memServer2.bind(new InetSocketAddress(4798)); - MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil - .getAddressMap("localhost:4799,localhost:4798")); + MemcachedClientBuilder builder = new XMemcachedClientBuilder( + AddrUtil.getAddressMap("localhost:4799,localhost:4798")); MemcachedClient client = builder.build(); client.setEnableHeartBeat(false); @@ -282,8 +288,8 @@ public void testNotFailureMode_NoStandbyNode() throws Exception { memServer1.setCodecFactory(new TextLineCodecFactory()); memServer1.bind(new InetSocketAddress(4799)); - MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil - .getAddressMap("localhost:4799")); + MemcachedClientBuilder builder = new XMemcachedClientBuilder( + AddrUtil.getAddressMap("localhost:4799")); MemcachedClient client = builder.build(); client.setEnableHeartBeat(false); @@ -320,8 +326,8 @@ public void testNotFailureMode_NoStandbyNode_TwoServers() throws Exception { memServer2.setCodecFactory(new TextLineCodecFactory()); memServer2.bind(new InetSocketAddress(4798)); - MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil - .getAddressMap("localhost:4799 localhost:4798")); + MemcachedClientBuilder builder = new XMemcachedClientBuilder( + AddrUtil.getAddressMap("localhost:4799 localhost:4798")); MemcachedClient client = builder.build(); client.setEnableHeartBeat(false); diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/KestrelClientIT.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/KestrelClientIT.java index cdfe5b134..024b9314b 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/KestrelClientIT.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/KestrelClientIT.java @@ -39,15 +39,15 @@ public void setUp() throws Exception { .getResourceAsProperties("test.properties"); MemcachedClientBuilder builder = newBuilder(); builder.setConnectionPoolSize(5); - //builder.getConfiguration().setSessionIdleTimeout(5); + // builder.getConfiguration().setSessionIdleTimeout(5); this.memcachedClient = builder.build(); this.memcachedClient.flushAll(); } private MemcachedClientBuilder newBuilder() { - MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil - .getAddresses(this.properties - .getProperty("test.kestrel.servers"))); + MemcachedClientBuilder builder = new XMemcachedClientBuilder( + AddrUtil.getAddresses( + this.properties.getProperty("test.kestrel.servers"))); // Use kestrel command factory builder.setCommandFactory(new KestrelCommandFactory()); return builder; @@ -61,8 +61,8 @@ public void testPrimitiveAsString() throws Exception { } // but get string for (int i = 0; i < 1000; i++) { - Assert.assertEquals(String.valueOf(i), this.memcachedClient - .get("queue1")); + Assert.assertEquals(String.valueOf(i), + this.memcachedClient.get("queue1")); } this.memcachedClient.setPrimitiveAsString(false); @@ -122,8 +122,8 @@ public void testSetAndGetObject() throws Exception { userDefinedClassList.add(new UserDefinedClass("b")); userDefinedClassList.add(new UserDefinedClass("c")); - Assert.assertTrue(this.memcachedClient.set("queue1", 0, - userDefinedClassList)); + Assert.assertTrue( + this.memcachedClient.set("queue1", 0, userDefinedClassList)); List userDefinedClassListFromMQ = (List) this.memcachedClient .get("queue1"); @@ -139,25 +139,25 @@ public void testBlockingFetch() throws Exception { Assert.assertEquals(1000, System.currentTimeMillis() - start, 100); Assert.assertTrue(this.memcachedClient.set("queue1", 0, "hello world")); - Assert.assertEquals("hello world", this.memcachedClient - .get("queue1/t=1000")); + Assert.assertEquals("hello world", + this.memcachedClient.get("queue1/t=1000")); } - - public void testPeek()throws Exception{ + + public void testPeek() throws Exception { Assert.assertNull(this.memcachedClient.get("queue1/peek")); this.memcachedClient.set("queue1", 0, 1); - Assert.assertEquals(1,this.memcachedClient.get("queue1/peek")); + Assert.assertEquals(1, this.memcachedClient.get("queue1/peek")); this.memcachedClient.set("queue1", 0, 10); - Assert.assertEquals(1,this.memcachedClient.get("queue1/peek")); + Assert.assertEquals(1, this.memcachedClient.get("queue1/peek")); this.memcachedClient.set("queue1", 0, 11); - Assert.assertEquals(1,this.memcachedClient.get("queue1/peek")); - - Assert.assertEquals(1,this.memcachedClient.get("queue1")); - Assert.assertEquals(10,this.memcachedClient.get("queue1/peek")); - Assert.assertEquals(10,this.memcachedClient.get("queue1")); - Assert.assertEquals(11,this.memcachedClient.get("queue1/peek")); - Assert.assertEquals(11,this.memcachedClient.get("queue1")); + Assert.assertEquals(1, this.memcachedClient.get("queue1/peek")); + + Assert.assertEquals(1, this.memcachedClient.get("queue1")); + Assert.assertEquals(10, this.memcachedClient.get("queue1/peek")); + Assert.assertEquals(10, this.memcachedClient.get("queue1")); + Assert.assertEquals(11, this.memcachedClient.get("queue1/peek")); + Assert.assertEquals(11, this.memcachedClient.get("queue1")); Assert.assertNull(this.memcachedClient.get("queue1/peek")); } @@ -174,8 +174,8 @@ public void testDelete() throws Exception { public void testReliableFetch() throws Exception { Assert.assertTrue(this.memcachedClient.set("queue1", 0, "hello world")); - Assert.assertEquals("hello world", this.memcachedClient - .get("queue1/open")); + Assert.assertEquals("hello world", + this.memcachedClient.get("queue1/open")); // close connection this.memcachedClient.shutdown(); // still can fetch it @@ -244,7 +244,6 @@ public void run() { } } - public void ignoreTestConcurrentAccess() throws Exception { int threadCount = 100; CyclicBarrier cyclicBarrier = new CyclicBarrier(threadCount + 1); @@ -255,11 +254,11 @@ public void ignoreTestConcurrentAccess() throws Exception { cyclicBarrier.await(); } - - public void testHearBeat()throws Exception{ - Thread.sleep(30*1000); + + public void testHearBeat() throws Exception { + Thread.sleep(30 * 1000); this.memcachedClient.set("queue1", 0, "hello"); - assertEquals("hello",this.memcachedClient.get("queue1")); + assertEquals("hello", this.memcachedClient.get("queue1")); } } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/MockMemcachedSession.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/MockMemcachedSession.java index cdc8f1326..4503cb921 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/MockMemcachedSession.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/MockMemcachedSession.java @@ -4,17 +4,17 @@ import net.rubyeye.xmemcached.networking.MemcachedSession; import net.rubyeye.xmemcached.utils.InetSocketAddressWrapper; -public class MockMemcachedSession extends MockSession implements MemcachedSession { - +public class MockMemcachedSession extends MockSession + implements + MemcachedSession { public MockMemcachedSession(int port) { super(port); } - public void setAllowReconnect(boolean allow) { // TODO Auto-generated method stub - + } public boolean isAllowReconnect() { @@ -24,18 +24,20 @@ public boolean isAllowReconnect() { public void setBufferAllocator(BufferAllocator allocator) { // TODO Auto-generated method stub - + } public InetSocketAddressWrapper getInetSocketAddressWrapper() { - InetSocketAddressWrapper inetSocketAddressWrapper = new InetSocketAddressWrapper(getRemoteSocketAddress(), 1, 1, null); - inetSocketAddressWrapper.setRemoteAddressStr("localhost/127.0.0.1:" + this.port); + InetSocketAddressWrapper inetSocketAddressWrapper = new InetSocketAddressWrapper( + getRemoteSocketAddress(), 1, 1, null); + inetSocketAddressWrapper + .setRemoteAddressStr("localhost/127.0.0.1:" + this.port); return inetSocketAddressWrapper; } public void destroy() { // TODO Auto-generated method stub - + } public int getWeight() { @@ -50,7 +52,7 @@ public int getOrder() { public void quit() { // TODO Auto-generated method stub - + } public boolean isAuthFailed() { @@ -60,7 +62,7 @@ public boolean isAuthFailed() { public void setAuthFailed(boolean authFailed) { // TODO Auto-generated method stub - + } } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/MockSession.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/MockSession.java index 9e7182f63..f3f74ef08 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/MockSession.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/MockSession.java @@ -175,7 +175,6 @@ public long getSessionTimeout() { public void setSessionTimeout(long sessionTimeout) { } - public Object setAttributeIfAbsent(String key, Object value) { return null; } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/StandardHashMemcachedClientIT.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/StandardHashMemcachedClientIT.java index 899572a8f..9839ff985 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/StandardHashMemcachedClientIT.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/StandardHashMemcachedClientIT.java @@ -24,8 +24,8 @@ public class StandardHashMemcachedClientIT extends XMemcachedClientIT { @Override public MemcachedClientBuilder createBuilder() throws Exception { MemcachedClientBuilder builder = new XMemcachedClientBuilder( - AddrUtil.getAddresses(this.properties - .getProperty("test.memcached.servers"))); + AddrUtil.getAddresses( + this.properties.getProperty("test.memcached.servers"))); // builder.setConnectionPoolSize(Runtime.getRuntime().availableProcessors()); return builder; } @@ -59,8 +59,8 @@ public void testLargeObject() throws Exception { fail(); } catch (MemcachedServerException exception) { - Assert.assertTrue(exception.getMessage().contains( - "object too large for cache")); + Assert.assertTrue(exception.getMessage() + .contains("object too large for cache")); } } String readLargeObject = memcachedClient.get(KEY_LARGE_OBJECT); @@ -197,9 +197,8 @@ public void testDecrWithNoReply() throws Exception { @Override public MemcachedClientBuilder createWeightedBuilder() throws Exception { - List addressList = AddrUtil - .getAddresses(this.properties - .getProperty("test.memcached.servers")); + List addressList = AddrUtil.getAddresses( + this.properties.getProperty("test.memcached.servers")); int[] weights = new int[addressList.size()]; for (int i = 0; i < weights.length; i++) { weights[i] = i + 1; diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientIT.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientIT.java index aa1f418f2..5b122d793 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientIT.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientIT.java @@ -147,7 +147,8 @@ public void call() throws Exception { new TooLongKeyChecker(memcachedClient) { @Override public void call() throws Exception { - int keyLength = memcachedClient.getProtocol() == Protocol.Text ? 256 + int keyLength = memcachedClient.getProtocol() == Protocol.Text + ? 256 : 65536; StringBuilder sb = new StringBuilder(); for (int i = 0; i < keyLength; i++) { @@ -212,7 +213,8 @@ public void call() throws Exception { new TooLongKeyChecker(memcachedClient) { @Override public void call() throws Exception { - int keyLength = memcachedClient.getProtocol() == Protocol.Text ? 256 + int keyLength = memcachedClient.getProtocol() == Protocol.Text + ? 256 : 65536; StringBuilder sb = new StringBuilder(); for (int i = 0; i < keyLength; i++) { @@ -256,7 +258,8 @@ public void call() throws Exception { new TooLongKeyChecker(memcachedClient) { @Override public void call() throws Exception { - int keyLength = memcachedClient.getProtocol() == Protocol.Text ? 256 + int keyLength = memcachedClient.getProtocol() == Protocol.Text + ? 256 : 65536; StringBuilder sb = new StringBuilder(); for (int i = 0; i < keyLength; i++) { @@ -268,8 +271,8 @@ public void call() throws Exception { } - public void testStoreCollection() throws TimeoutException, - InterruptedException, MemcachedException { + public void testStoreCollection() + throws TimeoutException, InterruptedException, MemcachedException { // store list List list = new ArrayList(); for (int i = 0; i < 100; i++) { @@ -342,7 +345,8 @@ public void call() throws Exception { new TooLongKeyChecker(memcachedClient) { @Override public void call() throws Exception { - int keyLength = memcachedClient.getProtocol() == Protocol.Text ? 256 + int keyLength = memcachedClient.getProtocol() == Protocol.Text + ? 256 : 65536; StringBuilder sb = new StringBuilder(); for (int i = 0; i < keyLength; i++) { @@ -406,7 +410,8 @@ public void call() throws Exception { new TooLongKeyChecker(memcachedClient) { @Override public void call() throws Exception { - int keyLength = memcachedClient.getProtocol() == Protocol.Text ? 256 + int keyLength = memcachedClient.getProtocol() == Protocol.Text + ? 256 : 65536; StringBuilder sb = new StringBuilder(); for (int i = 0; i < keyLength; i++) { @@ -429,8 +434,8 @@ public void call() throws Exception { @Override public void call() throws Exception { memcachedClient.set("name", 0, 1); - memcachedClient - .replace("name", 0, "xmemcached", mockTranscoder); + memcachedClient.replace("name", 0, "xmemcached", + mockTranscoder); assertEquals("xmemcached", memcachedClient.get("name", mockTranscoder)); @@ -476,7 +481,8 @@ public void call() throws Exception { new TooLongKeyChecker(memcachedClient) { @Override public void call() throws Exception { - int keyLength = memcachedClient.getProtocol() == Protocol.Text ? 256 + int keyLength = memcachedClient.getProtocol() == Protocol.Text + ? 256 : 65536; StringBuilder sb = new StringBuilder(); for (int i = 0; i < keyLength; i++) { @@ -593,7 +599,8 @@ public void call() throws Exception { new TooLongKeyChecker(memcachedClient) { @Override public void call() throws Exception { - int keyLength = memcachedClient.getProtocol() == Protocol.Text ? 256 + int keyLength = memcachedClient.getProtocol() == Protocol.Text + ? 256 : 65536; StringBuilder sb = new StringBuilder(); for (int i = 0; i < keyLength; i++) { @@ -654,18 +661,18 @@ public void testFlushAll() throws Exception { public void testSetLoggingLevelVerbosity() throws Exception { if (memcachedClient.getProtocol() == Protocol.Text || memcachedClient.getProtocol() == Protocol.Binary) { - memcachedClient.setLoggingLevelVerbosity( - AddrUtil.getAddresses( + memcachedClient.setLoggingLevelVerbosity(AddrUtil + .getAddresses( properties.getProperty("test.memcached.servers")) - .get(0), 2); - memcachedClient.setLoggingLevelVerbosityWithNoReply( - AddrUtil.getAddresses( + .get(0), 2); + memcachedClient.setLoggingLevelVerbosityWithNoReply(AddrUtil + .getAddresses( properties.getProperty("test.memcached.servers")) - .get(0), 3); - memcachedClient.setLoggingLevelVerbosityWithNoReply( - AddrUtil.getAddresses( + .get(0), 3); + memcachedClient.setLoggingLevelVerbosityWithNoReply(AddrUtil + .getAddresses( properties.getProperty("test.memcached.servers")) - .get(0), 0); + .get(0), 0); } else { // do nothing,binary protocol doesn't have verbosity protocol. } @@ -677,7 +684,8 @@ public void testIssue150() throws Exception { memcachedClient.incr("a", 1); fail(); } catch (MemcachedException e) { - // assertEquals("cannot increment or decrement non-numeric value",e.getMessage()); + // assertEquals("cannot increment or decrement non-numeric + // value",e.getMessage()); } memcachedClient.set("a", 0, "1"); assertEquals(3, memcachedClient.incr("a", 2)); @@ -739,7 +747,8 @@ public void call() throws Exception { new TooLongKeyChecker(memcachedClient) { @Override public void call() throws Exception { - int keyLength = memcachedClient.getProtocol() == Protocol.Text ? 256 + int keyLength = memcachedClient.getProtocol() == Protocol.Text + ? 256 : 65536; StringBuilder sb = new StringBuilder(); for (int i = 0; i < keyLength; i++) { @@ -803,7 +812,8 @@ public void call() throws Exception { new TooLongKeyChecker(memcachedClient) { @Override public void call() throws Exception { - int keyLength = memcachedClient.getProtocol() == Protocol.Text ? 256 + int keyLength = memcachedClient.getProtocol() == Protocol.Text + ? 256 : 65536; StringBuilder sb = new StringBuilder(); for (int i = 0; i < keyLength; i++) { @@ -872,7 +882,8 @@ public void call() throws Exception { new TooLongKeyChecker(memcachedClient) { @Override public void call() throws Exception { - int keyLength = memcachedClient.getProtocol() == Protocol.Text ? 256 + int keyLength = memcachedClient.getProtocol() == Protocol.Text + ? 256 : 65536; StringBuilder sb = new StringBuilder(); for (int i = 0; i < keyLength; i++) { @@ -895,17 +906,16 @@ public void testAutoReconnect() throws Exception { errorCommand = new MockErrorTextGetOneCommand(key, key.getBytes(), CommandType.GET_ONE, latch); } else { - errorCommand = new MockErrorBinaryGetOneCommand(key, - key.getBytes(), CommandType.GET_ONE, latch, OpCode.GET, - false); + errorCommand = new MockErrorBinaryGetOneCommand(key, key.getBytes(), + CommandType.GET_ONE, latch, OpCode.GET, false); } memcachedClient.getConnector().send((Command) errorCommand); latch.await(MemcachedClient.DEFAULT_OP_TIMEOUT, TimeUnit.MILLISECONDS); assertTrue(errorCommand.isDecoded()); // wait for reconnecting Thread.sleep(2000 * 3); - assertEquals(currentServerCount, memcachedClient.getAvaliableServers() - .size()); + assertEquals(currentServerCount, + memcachedClient.getAvaliableServers().size()); // It works assertEquals("dennis", memcachedClient.get(key)); } @@ -984,8 +994,8 @@ public void testRemoveAndAddServer() throws Exception { e.getMessage()); } - memcachedClient.addServer(properties - .getProperty("test.memcached.servers")); + memcachedClient + .addServer(properties.getProperty("test.memcached.servers")); synchronized (this) { while (memcachedClient.getAvaliableServers().size() < AddrUtil .getAddresses(servers).size()) { @@ -1015,8 +1025,8 @@ public void testWeightedServers() throws Exception { assertEquals(i, memcachedClient.get(String.valueOf(i))); } - List addressList = AddrUtil.getAddresses(properties - .getProperty("test.memcached.servers")); + List addressList = AddrUtil + .getAddresses(properties.getProperty("test.memcached.servers")); Map> newStats = memcachedClient .getStats(); for (InetSocketAddress address : addressList) { @@ -1037,7 +1047,8 @@ public void _testErrorCommand() throws Exception { Command nonexisCmd = new Command() { @Override - public boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { + public boolean decode(MemcachedTCPSession session, + ByteBuffer buffer) { return decodeError(ByteUtils.nextLine(buffer)); } @@ -1057,7 +1068,8 @@ public void encode() { assertNotNull(nonexisCmd.getException()); assertEquals("Nonexist command,check your memcached version please.", nonexisCmd.getException().getMessage()); - assertTrue(nonexisCmd.getException() instanceof UnknownCommandException); + assertTrue( + nonexisCmd.getException() instanceof UnknownCommandException); memcachedClient.set("name", 0, "dennis"); assertEquals("dennis", memcachedClient.get("name")); @@ -1067,8 +1079,8 @@ public void testGetAvaliableServers() { Collection servers = memcachedClient .getAvaliableServers(); - List serverList = AddrUtil.getAddresses(properties - .getProperty("test.memcached.servers")); + List serverList = AddrUtil + .getAddresses(properties.getProperty("test.memcached.servers")); assertEquals(servers.size(), serverList.size()); for (InetSocketAddress address : servers) { assertTrue(serverList.contains(address)); @@ -1184,40 +1196,40 @@ public void testIssue142() throws Exception { assertTrue(this.memcachedClient.delete("counter")); } -// public void testKeyIterator() throws Exception { -// if (memcachedClient.getProtocol() == Protocol.Text) { -// Collection avaliableServers = memcachedClient -// .getAvaliableServers(); -// InetSocketAddress address = avaliableServers.iterator().next(); -// KeyIterator it = memcachedClient.getKeyIterator(address); -// while (it.hasNext()) { -// memcachedClient.delete(it.next()); -// } -// it = memcachedClient.getKeyIterator(address); -// Assert.assertFalse(it.hasNext()); -// try { -// it.next(); -// Assert.fail(); -// } catch (NoSuchElementException e) { -// Assert.assertTrue(true); -// } -// for (int i = 0; i < 10; i++) { -// memcachedClient.set(String.valueOf(i), 0, i); -// } -// it = memcachedClient.getKeyIterator(address); -// Assert.assertTrue(it.hasNext()); -// Assert.assertEquals(address, it.getServerAddress()); -// while (it.hasNext()) { -// String key = it.next(); -// Assert.assertEquals(Integer.parseInt(key), -// memcachedClient.get(key)); -// } -// Assert.assertFalse(it.hasNext()); -// } else { -// // ignore -// } -// -// } + // public void testKeyIterator() throws Exception { + // if (memcachedClient.getProtocol() == Protocol.Text) { + // Collection avaliableServers = memcachedClient + // .getAvaliableServers(); + // InetSocketAddress address = avaliableServers.iterator().next(); + // KeyIterator it = memcachedClient.getKeyIterator(address); + // while (it.hasNext()) { + // memcachedClient.delete(it.next()); + // } + // it = memcachedClient.getKeyIterator(address); + // Assert.assertFalse(it.hasNext()); + // try { + // it.next(); + // Assert.fail(); + // } catch (NoSuchElementException e) { + // Assert.assertTrue(true); + // } + // for (int i = 0; i < 10; i++) { + // memcachedClient.set(String.valueOf(i), 0, i); + // } + // it = memcachedClient.getKeyIterator(address); + // Assert.assertTrue(it.hasNext()); + // Assert.assertEquals(address, it.getServerAddress()); + // while (it.hasNext()) { + // String key = it.next(); + // Assert.assertEquals(Integer.parseInt(key), + // memcachedClient.get(key)); + // } + // Assert.assertFalse(it.hasNext()); + // } else { + // // ignore + // } + // + // } public void testNamespace() throws Exception { String ns = "user-id"; @@ -1275,9 +1287,9 @@ public Void call(MemcachedClient client) }); } - - public void testNamespaceWithGetMulti()throws Exception{ - String ns="user"; + + public void testNamespaceWithGetMulti() throws Exception { + String ns = "user"; this.memcachedClient.withNamespace(ns, new MemcachedClientCallable() { @@ -1287,11 +1299,12 @@ public Void call(MemcachedClient client) client.set("a", 0, 1); client.set("b", 0, 2); client.set("c", 0, 3); - Map values = client.get(Arrays.asList("a","b","c")); - assertEquals(3,values.size()); - assertEquals(1,values.get("a")); - assertEquals(2,values.get("b")); - assertEquals(3,values.get("c")); + Map values = client + .get(Arrays.asList("a", "b", "c")); + assertEquals(3, values.size()); + assertEquals(1, values.get("a")); + assertEquals(2, values.get("b")); + assertEquals(3, values.get("c")); return null; } }); diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientWithKeyProviderIT.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientWithKeyProviderIT.java index 8075d68ce..d1b42060c 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientWithKeyProviderIT.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/XMemcachedClientWithKeyProviderIT.java @@ -32,17 +32,16 @@ public String process(String key) { public MemcachedClientBuilder createBuilder() throws Exception { MemcachedClientBuilder builder = new XMemcachedClientBuilder( - AddrUtil.getAddresses(this.properties - .getProperty("test.memcached.servers"))); + AddrUtil.getAddresses( + this.properties.getProperty("test.memcached.servers"))); ByteUtils.testing = true; return builder; } @Override public MemcachedClientBuilder createWeightedBuilder() throws Exception { - List addressList = AddrUtil - .getAddresses(this.properties - .getProperty("test.memcached.servers")); + List addressList = AddrUtil.getAddresses( + this.properties.getProperty("test.memcached.servers")); int[] weights = new int[addressList.size()]; for (int i = 0; i < weights.length; i++) { weights[i] = i + 1; diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/buffer/AbstractBufferAllocatorUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/buffer/AbstractBufferAllocatorUnitTest.java index f7f8f9095..ca641cb03 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/buffer/AbstractBufferAllocatorUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/buffer/AbstractBufferAllocatorUnitTest.java @@ -71,7 +71,7 @@ public void testAllocate() { assertEquals(0, buffer.position()); assertEquals(4, buffer.limit()); assertEquals(4, buffer.remaining()); - + buffer.clear(); assertEquals(64, buffer.capacity()); assertEquals(0, buffer.position()); diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/buffer/BufferAllocatorTestSuite.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/buffer/BufferAllocatorTestSuite.java index 8c4568fea..6b267bf78 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/buffer/BufferAllocatorTestSuite.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/buffer/BufferAllocatorTestSuite.java @@ -8,10 +8,10 @@ public class BufferAllocatorTestSuite { public static Test suite() { TestSuite suite = new TestSuite( "Test for net.rubyeye.xmemcached.test.unittest.buffer"); - //$JUnit-BEGIN$ + // $JUnit-BEGIN$ suite.addTestSuite(SimpleBufferAllocatorUnitTest.class); suite.addTestSuite(CachedBufferAllocatorUnitTest.class); - //$JUnit-END$ + // $JUnit-END$ return suite; } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/buffer/CachedBufferAllocatorUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/buffer/CachedBufferAllocatorUnitTest.java index 4cddfb294..c2a836fa0 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/buffer/CachedBufferAllocatorUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/buffer/CachedBufferAllocatorUnitTest.java @@ -1,9 +1,10 @@ package net.rubyeye.xmemcached.test.unittest.buffer; - import net.rubyeye.xmemcached.buffer.CachedBufferAllocator; -public class CachedBufferAllocatorUnitTest extends AbstractBufferAllocatorUnitTest { +public class CachedBufferAllocatorUnitTest + extends + AbstractBufferAllocatorUnitTest { public void createBufferAllocator() { this.allocator = CachedBufferAllocator.newInstance(); } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/buffer/SimpleBufferAllocatorUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/buffer/SimpleBufferAllocatorUnitTest.java index d7351275f..83b1f0523 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/buffer/SimpleBufferAllocatorUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/buffer/SimpleBufferAllocatorUnitTest.java @@ -2,8 +2,9 @@ import net.rubyeye.xmemcached.buffer.SimpleBufferAllocator; -public class SimpleBufferAllocatorUnitTest extends - AbstractBufferAllocatorUnitTest { +public class SimpleBufferAllocatorUnitTest + extends + AbstractBufferAllocatorUnitTest { @Override public void createBufferAllocator() { diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/codec/MemcachedDecoderUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/codec/MemcachedDecoderUnitTest.java index cf26aff6e..3d3379475 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/codec/MemcachedDecoderUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/codec/MemcachedDecoderUnitTest.java @@ -21,11 +21,12 @@ public class MemcachedDecoderUnitTest extends TestCase { public void testDecode() { decoder = new MemcachedCodecFactory().getDecoder(); MemcachedTCPSession session = buildSession(); - Command versionCommand = new TextCommandFactory().createVersionCommand( - new CountDownLatch(1), null); + Command versionCommand = new TextCommandFactory() + .createVersionCommand(new CountDownLatch(1), null); session.addCommand(versionCommand); - Command decodedCommand = (Command) decoder.decode(IoBuffer - .wrap(ByteBuffer.wrap("VERSION 1.28\r\n".getBytes())), session); + Command decodedCommand = (Command) decoder.decode( + IoBuffer.wrap(ByteBuffer.wrap("VERSION 1.28\r\n".getBytes())), + session); assertSame(decodedCommand, versionCommand); assertEquals("1.28", decodedCommand.getResult()); } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/codec/MemcachedEncoderUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/codec/MemcachedEncoderUnitTest.java index 3ff838058..479fee2e8 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/codec/MemcachedEncoderUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/codec/MemcachedEncoderUnitTest.java @@ -16,8 +16,8 @@ public class MemcachedEncoderUnitTest extends TestCase { public void testEncode() { this.encoder = new MemcachedCodecFactory().getEncoder(); - Command command = new TextCommandFactory().createVersionCommand( - new CountDownLatch(1), null); + Command command = new TextCommandFactory() + .createVersionCommand(new CountDownLatch(1), null); command.encode(); IoBuffer buffer = this.encoder.encode(command, null); assertEquals(buffer.buf(), ServerAddressAware.VERSION); diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryAppendPrependCommandUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryAppendPrependCommandUnitTest.java index ac66ab9a9..bb42ef128 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryAppendPrependCommandUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryAppendPrependCommandUnitTest.java @@ -6,8 +6,9 @@ import net.rubyeye.xmemcached.command.binary.OpCode; import net.rubyeye.xmemcached.utils.ByteUtils; -public class BinaryAppendPrependCommandUnitTest extends - BaseBinaryCommandUnitTest { +public class BinaryAppendPrependCommandUnitTest + extends + BaseBinaryCommandUnitTest { String key = "hello"; byte[] keyBytes = ByteUtils.getBytes(this.key); String value = "!"; @@ -35,8 +36,8 @@ public void testAppendEncodeAndDecode() { buffer = constructResponse(OpCode.APPEND.fieldValue(), (short) 0, (byte) 0, (byte) 0, (short) 0x0005, 0, 0, 1L, null, null, null); - command = this.commandFactory.createAppendCommand(this.key, this.keyBytes, this.value, - this.noreply, this.transcoder); + command = this.commandFactory.createAppendCommand(this.key, + this.keyBytes, this.value, this.noreply, this.transcoder); assertTrue(command.decode(null, buffer)); assertFalse((Boolean) command.getResult()); assertEquals(0, buffer.remaining()); @@ -64,8 +65,8 @@ public void testPrependEncodeAndDecode() { buffer = constructResponse(OpCode.PREPEND.fieldValue(), (short) 0, (byte) 0, (byte) 0, (short) 0x0005, 0, 0, 1L, null, null, null); - command = this.commandFactory.createPrependCommand(this.key, this.keyBytes, - this.value, this.noreply, this.transcoder); + command = this.commandFactory.createPrependCommand(this.key, + this.keyBytes, this.value, this.noreply, this.transcoder); assertTrue(command.decode(null, buffer)); assertFalse((Boolean) command.getResult()); assertEquals(0, buffer.remaining()); diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryCASCommandUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryCASCommandUnitTest.java index 638de5dd4..3cfb6e9bc 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryCASCommandUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryCASCommandUnitTest.java @@ -14,8 +14,9 @@ public class BinaryCASCommandUnitTest extends BaseBinaryCommandUnitTest { public void testAddEncodeAndDecode() { - Command command = this.commandFactory.createCASCommand(this.key, this.keyBytes, - 0, this.value, 9L, this.noreply, this.transcoder); + Command command = this.commandFactory.createCASCommand(this.key, + this.keyBytes, 0, this.value, 9L, this.noreply, + this.transcoder); command.encode(); ByteBuffer encodeBuffer = command.getIoBuffer().buf(); @@ -27,17 +28,17 @@ public void testAddEncodeAndDecode() { assertEquals(OpCode.SET.fieldValue(), opCode); ByteBuffer buffer = constructResponse(OpCode.SET.fieldValue(), - (short) 0, (byte) 0, (byte) 0, (short) 0, 0, 0, 10L, null, - null, null); + (short) 0, (byte) 0, (byte) 0, (short) 0, 0, 0, 10L, null, null, + null); assertTrue(command.decode(null, buffer)); assertTrue((Boolean) command.getResult()); assertEquals(0, buffer.remaining()); - buffer = constructResponse(OpCode.SET.fieldValue(), (short) 0, - (byte) 0, (byte) 0, (short) 0x0005, 0, 0, 0L, null, null, null); - command = this.commandFactory.createCASCommand(this.key, this.keyBytes, 0, this.value, - 9L, this.noreply, this.transcoder); + buffer = constructResponse(OpCode.SET.fieldValue(), (short) 0, (byte) 0, + (byte) 0, (short) 0x0005, 0, 0, 0L, null, null, null); + command = this.commandFactory.createCASCommand(this.key, this.keyBytes, + 0, this.value, 9L, this.noreply, this.transcoder); assertTrue(command.decode(null, buffer)); assertFalse((Boolean) command.getResult()); assertEquals(0, buffer.remaining()); diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryCommandAllTests.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryCommandAllTests.java index 6f9fd362d..676d6c1c2 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryCommandAllTests.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryCommandAllTests.java @@ -8,7 +8,7 @@ public class BinaryCommandAllTests { public static Test suite() { TestSuite suite = new TestSuite( "Test for net.rubyeye.xmemcached.test.unittest.commands.binary"); - //$JUnit-BEGIN$ + // $JUnit-BEGIN$ suite.addTestSuite(BinaryGetCommandUnitTest.class); suite.addTestSuite(BinaryDeleteCommandUnitTest.class); suite.addTestSuite(BinaryStoreCommandUnitTest.class); @@ -17,7 +17,7 @@ public static Test suite() { suite.addTestSuite(BinaryStatsCommandUnitTest.class); suite.addTestSuite(BinaryGetMultiCommandUnitTest.class); suite.addTestSuite(BinaryCASCommandUnitTest.class); - //$JUnit-END$ + // $JUnit-END$ return suite; } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryDeleteCommandUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryDeleteCommandUnitTest.java index 787eac704..48e3283ce 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryDeleteCommandUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryDeleteCommandUnitTest.java @@ -34,8 +34,7 @@ public void testDeleteEncodeAndDecode() { buffer = this.constructResponse(OpCode.DELETE.fieldValue(), (short) 0, (byte) 0, (byte) 0, (short) 0x0005, 0, 0, 1L, null, null, null); command = this.commandFactory.createDeleteCommand(this.key, - this.keyBytes, 0, 999L, - this.noreply); + this.keyBytes, 0, 999L, this.noreply); assertTrue(command.decode(null, buffer)); assertFalse((Boolean) command.getResult()); assertEquals(0, buffer.remaining()); diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryGetAndTouchCommandUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryGetAndTouchCommandUnitTest.java index c396da029..e65daa578 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryGetAndTouchCommandUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryGetAndTouchCommandUnitTest.java @@ -7,15 +7,17 @@ import net.rubyeye.xmemcached.transcoders.CachedData; import net.rubyeye.xmemcached.utils.ByteUtils; -public class BinaryGetAndTouchCommandUnitTest extends BaseBinaryCommandUnitTest { +public class BinaryGetAndTouchCommandUnitTest + extends + BaseBinaryCommandUnitTest { String key = "hello"; byte[] keyBytes = ByteUtils.getBytes(this.key); boolean noreply = false; public void testGetEncodeAndDecode() { - Command command = this.commandFactory.createGetAndTouchCommand( - this.key, this.keyBytes, null, 10, false); + Command command = this.commandFactory.createGetAndTouchCommand(this.key, + this.keyBytes, null, 10, false); command.encode(); ByteBuffer encodeBuffer = command.getIoBuffer().buf(); @@ -31,8 +33,8 @@ public void testGetEncodeAndDecode() { assertEquals(33, buffer.capacity()); assertTrue(command.decode(null, buffer)); - assertEquals("world", this.transcoder.decode((CachedData) command - .getResult())); + assertEquals("world", + this.transcoder.decode((CachedData) command.getResult())); assertEquals(0, buffer.remaining()); buffer = constructResponse(OpCode.GAT.fieldValue(), (short) 0, diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryGetCommandUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryGetCommandUnitTest.java index 07eb407bf..caa0b7ddd 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryGetCommandUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryGetCommandUnitTest.java @@ -15,8 +15,8 @@ public class BinaryGetCommandUnitTest extends BaseBinaryCommandUnitTest { public void testGetEncodeAndDecode() { - Command command = this.commandFactory.createGetCommand(this.key, this.keyBytes, - CommandType.GET_ONE, this.transcoder); + Command command = this.commandFactory.createGetCommand(this.key, + this.keyBytes, CommandType.GET_ONE, this.transcoder); command.encode(); ByteBuffer encodeBuffer = command.getIoBuffer().buf(); assertNotNull(encodeBuffer); @@ -31,8 +31,8 @@ public void testGetEncodeAndDecode() { assertEquals(33, buffer.capacity()); assertTrue(command.decode(null, buffer)); - assertEquals("world", this.transcoder.decode((CachedData) command - .getResult())); + assertEquals("world", + this.transcoder.decode((CachedData) command.getResult())); assertEquals(0, buffer.remaining()); buffer = constructResponse(OpCode.GET.fieldValue(), (short) 0, diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryGetMultiCommandUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryGetMultiCommandUnitTest.java index 2cd0b4f7b..a78ae67b2 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryGetMultiCommandUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryGetMultiCommandUnitTest.java @@ -35,7 +35,7 @@ public void testEncodeDecode() { // decode ByteBuffer[] buffers = new ByteBuffer[10]; - int capacity=0; + int capacity = 0; // First 9 buffer is getkq for (int i = 0; i < 9; i++) { int flag = 0; @@ -44,51 +44,54 @@ public void testEncodeDecode() { byte[] keyBytes = ByteUtils.getBytes(key); if (i % 2 == 0) { // value==key - buffers[i] = constructResponse(OpCode.GET_KEY_QUIETLY - .fieldValue(), (short) 1, (byte) 0x04, (byte) 0, - (short) 0, 6, 0, 1L, flagBytes, keyBytes, keyBytes); + buffers[i] = constructResponse( + OpCode.GET_KEY_QUIETLY.fieldValue(), (short) 1, + (byte) 0x04, (byte) 0, (short) 0, 6, 0, 1L, flagBytes, + keyBytes, keyBytes); } else { // key not found - buffers[i] = constructResponse(OpCode.GET_KEY_QUIETLY - .fieldValue(), (short) 1, (byte) 0x04, (byte) 0, - (short) 0x0001, 5, 0, 1L, flagBytes, keyBytes, null); + buffers[i] = constructResponse( + OpCode.GET_KEY_QUIETLY.fieldValue(), (short) 1, + (byte) 0x04, (byte) 0, (short) 0x0001, 5, 0, 1L, + flagBytes, keyBytes, null); } - capacity+=buffers[i].capacity(); + capacity += buffers[i].capacity(); } // last buffer is getk int flag = 0; byte[] flagBytes = this.transcoderUtils.encodeInt(flag); String key = String.valueOf(9); byte[] keyBytes = ByteUtils.getBytes(key); - buffers[9] = constructResponse(OpCode.GET_KEY.fieldValue(), - (short) 1, (byte) 0x04, (byte) 0, (short) 0x0001, 5, 0, 1L, - flagBytes, keyBytes, null); - - capacity+=buffers[9].capacity(); - - ByteBuffer totalBuffer=ByteBuffer.allocate(capacity); - for(ByteBuffer buffer:buffers){ + buffers[9] = constructResponse(OpCode.GET_KEY.fieldValue(), (short) 1, + (byte) 0x04, (byte) 0, (short) 0x0001, 5, 0, 1L, flagBytes, + keyBytes, null); + + capacity += buffers[9].capacity(); + + ByteBuffer totalBuffer = ByteBuffer.allocate(capacity); + for (ByteBuffer buffer : buffers) { totalBuffer.put(buffer); } totalBuffer.flip(); - - assertTrue(command.decode(null,totalBuffer)); - Map result=(Map)command.getResult(); - + + assertTrue(command.decode(null, totalBuffer)); + Map result = (Map) command + .getResult(); + assertNotNull(result); - assertEquals(5,result.size()); - - for(int i=0;i<10;i++){ - if(i%2==0){ + assertEquals(5, result.size()); + + for (int i = 0; i < 10; i++) { + if (i % 2 == 0) { assertNotNull(result.get(String.valueOf(i))); - assertEquals(String.valueOf(i),this.transcoder.decode(result.get(String.valueOf(i)))); - }else{ + assertEquals(String.valueOf(i), + this.transcoder.decode(result.get(String.valueOf(i)))); + } else { assertNull(result.get(String.valueOf(i))); } } - - assertEquals(0,totalBuffer.remaining()); - + + assertEquals(0, totalBuffer.remaining()); } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryIncrDecrUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryIncrDecrUnitTest.java index 8a03954f3..4216550c8 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryIncrDecrUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryIncrDecrUnitTest.java @@ -16,8 +16,9 @@ public class BinaryIncrDecrUnitTest extends BaseBinaryCommandUnitTest { int exp = 2 * 3600; public void testIncrementEncodeDecode() { - Command command = this.commandFactory.createIncrDecrCommand(this.key, this.keyBytes, - this.delta, this.initial, this.exp, CommandType.INCR, false); + Command command = this.commandFactory.createIncrDecrCommand(this.key, + this.keyBytes, this.delta, this.initial, this.exp, + CommandType.INCR, false); command.encode(); ByteBuffer encodeBuffer = command.getIoBuffer().buf(); assertNotNull(encodeBuffer); @@ -25,29 +26,31 @@ public void testIncrementEncodeDecode() { byte opCode = encodeBuffer.get(1); assertEquals(OpCode.INCREMENT.fieldValue(), opCode); - ByteBuffer buffer = constructResponse(OpCode.INCREMENT.fieldValue(), (short) 0, - (byte) 0, (byte) 0, (short) 0, 0x00000008, 0, 5L, null, null, - this.transcoderUtils.encodeLong(0L)); - assertEquals(32,buffer.capacity()); + ByteBuffer buffer = constructResponse(OpCode.INCREMENT.fieldValue(), + (short) 0, (byte) 0, (byte) 0, (short) 0, 0x00000008, 0, 5L, + null, null, this.transcoderUtils.encodeLong(0L)); + assertEquals(32, buffer.capacity()); assertTrue(command.decode(null, buffer)); - assertEquals(0L,command.getResult()); - assertEquals(0,buffer.remaining()); - - command = this.commandFactory.createIncrDecrCommand(this.key, this.keyBytes, - this.delta, this.initial, this.exp, CommandType.INCR, false); + assertEquals(0L, command.getResult()); + assertEquals(0, buffer.remaining()); + + command = this.commandFactory.createIncrDecrCommand(this.key, + this.keyBytes, this.delta, this.initial, this.exp, + CommandType.INCR, false); buffer = constructResponse(OpCode.INCREMENT.fieldValue(), (short) 0, (byte) 0, (byte) 0, (short) 0, 0x00000008, 0, 5L, null, null, this.transcoderUtils.encodeLong(9999L)); - assertEquals(32,buffer.capacity()); + assertEquals(32, buffer.capacity()); assertTrue(command.decode(null, buffer)); - assertEquals(9999L,command.getResult()); - assertEquals(0,buffer.remaining()); + assertEquals(9999L, command.getResult()); + assertEquals(0, buffer.remaining()); } - + public void testDecrementEncodeDecode() { - Command command = this.commandFactory.createIncrDecrCommand(this.key, this.keyBytes, - this.delta, this.initial, this.exp, CommandType.DECR, false); + Command command = this.commandFactory.createIncrDecrCommand(this.key, + this.keyBytes, this.delta, this.initial, this.exp, + CommandType.DECR, false); command.encode(); ByteBuffer encodeBuffer = command.getIoBuffer().buf(); assertNotNull(encodeBuffer); @@ -55,23 +58,24 @@ public void testDecrementEncodeDecode() { byte opCode = encodeBuffer.get(1); assertEquals(OpCode.DECREMENT.fieldValue(), opCode); - ByteBuffer buffer = constructResponse(OpCode.DECREMENT.fieldValue(), (short) 0, - (byte) 0, (byte) 0, (short) 0, 0x00000008, 0, 5L, null, null, - this.transcoderUtils.encodeLong(0L)); - assertEquals(32,buffer.capacity()); + ByteBuffer buffer = constructResponse(OpCode.DECREMENT.fieldValue(), + (short) 0, (byte) 0, (byte) 0, (short) 0, 0x00000008, 0, 5L, + null, null, this.transcoderUtils.encodeLong(0L)); + assertEquals(32, buffer.capacity()); assertTrue(command.decode(null, buffer)); - assertEquals(0L,command.getResult()); - assertEquals(0,buffer.remaining()); - - command = this.commandFactory.createIncrDecrCommand(this.key, this.keyBytes, - this.delta, this.initial, this.exp, CommandType.DECR, false); + assertEquals(0L, command.getResult()); + assertEquals(0, buffer.remaining()); + + command = this.commandFactory.createIncrDecrCommand(this.key, + this.keyBytes, this.delta, this.initial, this.exp, + CommandType.DECR, false); buffer = constructResponse(OpCode.DECREMENT.fieldValue(), (short) 0, (byte) 0, (byte) 0, (short) 0, 0x00000008, 0, 5L, null, null, this.transcoderUtils.encodeLong(9999L)); - assertEquals(32,buffer.capacity()); + assertEquals(32, buffer.capacity()); assertTrue(command.decode(null, buffer)); - assertEquals(9999L,command.getResult()); - assertEquals(0,buffer.remaining()); + assertEquals(9999L, command.getResult()); + assertEquals(0, buffer.remaining()); } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryStatsCommandUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryStatsCommandUnitTest.java index 827ed7646..a9479e27d 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryStatsCommandUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryStatsCommandUnitTest.java @@ -25,8 +25,8 @@ public void testEncodeDecode() { String key = String.valueOf(i); buffers[i] = constructResponse(OpCode.STAT.fieldValue(), (short) key.length(), (byte) 0, (byte) 0, (short) 0, - 2 * key.length(), 0, 0L, null, key.getBytes(), key - .getBytes()); + 2 * key.length(), 0, 0L, null, key.getBytes(), + key.getBytes()); capacity += buffers[i].capacity(); } @@ -39,17 +39,15 @@ public void testEncodeDecode() { totalBuffer.flip(); assertTrue(command.decode(null, totalBuffer)); - Map result = (Map) command - .getResult(); + Map result = (Map) command.getResult(); assertNotNull(result); assertTrue(result.size() > 0); assertEquals(5, result.size()); - - for(Map.Entry entry:result.entrySet()){ - assertEquals(entry.getKey(),entry.getValue()); + + for (Map.Entry entry : result.entrySet()) { + assertEquals(entry.getKey(), entry.getValue()); } - - + } } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryStoreCommandUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryStoreCommandUnitTest.java index 939f0f6ea..db3ecab5c 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryStoreCommandUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/binary/BinaryStoreCommandUnitTest.java @@ -14,8 +14,8 @@ public class BinaryStoreCommandUnitTest extends BaseBinaryCommandUnitTest { public void testAddEncodeAndDecode() { - Command command = this.commandFactory.createAddCommand(this.key, this.keyBytes, - 0, this.value, this.noreply, this.transcoder); + Command command = this.commandFactory.createAddCommand(this.key, + this.keyBytes, 0, this.value, this.noreply, this.transcoder); command.encode(); ByteBuffer encodeBuffer = command.getIoBuffer().buf(); @@ -33,10 +33,10 @@ public void testAddEncodeAndDecode() { assertTrue((Boolean) command.getResult()); assertEquals(0, buffer.remaining()); - buffer = constructResponse(OpCode.ADD.fieldValue(), (short) 0, - (byte) 0, (byte) 0, (short) 0x0005, 0, 0, 1L, null, null, null); - command = this.commandFactory.createAddCommand(this.key, this.keyBytes, 0, this.value, - this.noreply, this.transcoder); + buffer = constructResponse(OpCode.ADD.fieldValue(), (short) 0, (byte) 0, + (byte) 0, (short) 0x0005, 0, 0, 1L, null, null, null); + command = this.commandFactory.createAddCommand(this.key, this.keyBytes, + 0, this.value, this.noreply, this.transcoder); assertTrue(command.decode(null, buffer)); assertFalse((Boolean) command.getResult()); assertEquals(0, buffer.remaining()); @@ -65,8 +65,8 @@ public void testReplaceEncodeAndDecode() { buffer = constructResponse(OpCode.REPLACE.fieldValue(), (short) 0, (byte) 0, (byte) 0, (short) 0x0005, 0, 0, 1L, null, null, null); - command = this.commandFactory.createReplaceCommand(this.key, this.keyBytes, 0, this.value, - this.noreply, this.transcoder); + command = this.commandFactory.createReplaceCommand(this.key, + this.keyBytes, 0, this.value, this.noreply, this.transcoder); assertTrue(command.decode(null, buffer)); assertFalse((Boolean) command.getResult()); assertEquals(0, buffer.remaining()); @@ -74,8 +74,8 @@ public void testReplaceEncodeAndDecode() { public void testSetEncodeAndDecode() { - Command command = this.commandFactory.createSetCommand(this.key, this.keyBytes, - 0, this.value, this.noreply, this.transcoder); + Command command = this.commandFactory.createSetCommand(this.key, + this.keyBytes, 0, this.value, this.noreply, this.transcoder); command.encode(); ByteBuffer encodeBuffer = command.getIoBuffer().buf(); @@ -93,10 +93,10 @@ public void testSetEncodeAndDecode() { assertTrue((Boolean) command.getResult()); assertEquals(0, buffer.remaining()); - buffer = constructResponse(OpCode.SET.fieldValue(), (short) 0, - (byte) 0, (byte) 0, (short) 0x0005, 0, 0, 1L, null, null, null); - command = this.commandFactory.createSetCommand(this.key, this.keyBytes, 0, this.value, - this.noreply, this.transcoder); + buffer = constructResponse(OpCode.SET.fieldValue(), (short) 0, (byte) 0, + (byte) 0, (short) 0x0005, 0, 0, 1L, null, null, null); + command = this.commandFactory.createSetCommand(this.key, this.keyBytes, + 0, this.value, this.noreply, this.transcoder); assertTrue(command.decode(null, buffer)); assertFalse((Boolean) command.getResult()); assertEquals(0, buffer.remaining()); diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/factory/TextCommandFactoryTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/factory/TextCommandFactoryTest.java index 15733678e..e4e90ef1d 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/factory/TextCommandFactoryTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/factory/TextCommandFactoryTest.java @@ -22,8 +22,7 @@ public class TextCommandFactoryTest extends TestCase { @Override protected void setUp() throws Exception { - this.commandFactory = new TextCommandFactory( - ); + this.commandFactory = new TextCommandFactory(); } public void testCreateDeleteCommand() { @@ -34,8 +33,7 @@ public void testCreateDeleteCommand() { keyBytes, time, 0, false); deleteCmd.encode(); assertEquals(CommandType.DELETE, deleteCmd.getCommandType()); - String commandStr = new String(deleteCmd.getIoBuffer().buf() - .array()); + String commandStr = new String(deleteCmd.getIoBuffer().buf().array()); String expectedStr = "delete test\r\n"; @@ -43,10 +41,10 @@ public void testCreateDeleteCommand() { } public void testCreateVersionCommand() { - Command versionCmd = this.commandFactory.createVersionCommand(new CountDownLatch(1),null); + Command versionCmd = this.commandFactory + .createVersionCommand(new CountDownLatch(1), null); versionCmd.encode(); - String commandStr = new String(versionCmd.getIoBuffer().buf() - .array()); + String commandStr = new String(versionCmd.getIoBuffer().buf().array()); assertEquals("version\r\n", commandStr); assertEquals(CommandType.VERSION, versionCmd.getCommandType()); } @@ -57,12 +55,12 @@ public void testCreateStoreCommand() { byte[] keyBytes = ByteUtils.getBytes(key); int exp = 0; Transcoder transcoder = new StringTranscoder(); - Command storeCmd = this.commandFactory.createSetCommand(key, keyBytes, exp, value,false, transcoder); + Command storeCmd = this.commandFactory.createSetCommand(key, keyBytes, + exp, value, false, transcoder); storeCmd.encode(); assertFalse(storeCmd.isNoreply()); assertEquals(CommandType.SET, storeCmd.getCommandType()); - String commandStr = new String(storeCmd.getIoBuffer().buf() - .array()); + String commandStr = new String(storeCmd.getIoBuffer().buf().array()); String expectedStr = "set test " + StringTranscoder.STRING_FLAG + " 0 4\r\ntest\r\n"; @@ -76,8 +74,7 @@ public void testCreateGetCommand() { CommandType.GET_ONE, null); getCmd.encode(); assertEquals(CommandType.GET_ONE, getCmd.getCommandType()); - String commandStr = new String(getCmd.getIoBuffer().buf() - .array()); + String commandStr = new String(getCmd.getIoBuffer().buf().array()); String expectedStr = "get test\r\n"; assertEquals(expectedStr, commandStr); @@ -88,11 +85,10 @@ public void testCreateIncrDecrCommand() { byte[] keyBytes = ByteUtils.getBytes(key); int num = 10; Command inCr = this.commandFactory.createIncrDecrCommand(key, keyBytes, - num, 0,0, CommandType.INCR, false); + num, 0, 0, CommandType.INCR, false); inCr.encode(); assertEquals(CommandType.INCR, inCr.getCommandType()); - String commandStr = new String(inCr.getIoBuffer().buf() - .array()); + String commandStr = new String(inCr.getIoBuffer().buf().array()); String expectedStr = "incr test 10\r\n"; assertEquals(expectedStr, commandStr); @@ -110,8 +106,7 @@ public void testCreateGetMultiCommand() { CommandType.GET_MANY, null); cmd.encode(); assertEquals(CommandType.GET_MANY, cmd.getCommandType()); - String commandStr = new String(cmd.getIoBuffer().buf() - .array()); + String commandStr = new String(cmd.getIoBuffer().buf().array()); String expectedStr = "get a b c a\r\n"; assertEquals(expectedStr, commandStr); diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/BaseTextCommandUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/BaseTextCommandUnitTest.java index 795b9ad60..e88229f75 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/BaseTextCommandUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/BaseTextCommandUnitTest.java @@ -27,20 +27,22 @@ protected void checkDecodeNullAndNotLineByteBuffer(Command command) { assertFalse(command.decode(null, ByteBuffer.wrap("test".getBytes()))); } - protected void checkDecodeInvalidLine(Command command,String key,String invalidLine) { + protected void checkDecodeInvalidLine(Command command, String key, + String invalidLine) { try { command.decode(null, ByteBuffer.wrap(invalidLine.getBytes())); fail(); } catch (MemcachedDecodeException e) { assertTrue(true); - assertEquals(DECODE_ERROR_SESSION_WILL_BE_CLOSED + ",key="+key+",server returns=" - + invalidLine.replace("\r\n", ""), e.getMessage()); + assertEquals(DECODE_ERROR_SESSION_WILL_BE_CLOSED + ",key=" + key + + ",server returns=" + invalidLine.replace("\r\n", ""), + e.getMessage()); } } - - public void testDecodeError(){ - + + public void testDecodeError() { + } protected void checkDecodeValidLine(Command command, String validLine) { @@ -48,7 +50,7 @@ protected void checkDecodeValidLine(Command command, String validLine) { } protected void checkByteBufferEquals(Command command, String line) { - assertEquals(ByteBuffer.wrap(line.getBytes()), command.getIoBuffer() - .buf()); + assertEquals(ByteBuffer.wrap(line.getBytes()), + command.getIoBuffer().buf()); } } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextCommandsAllTests.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextCommandsAllTests.java index ea566f397..579580694 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextCommandsAllTests.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextCommandsAllTests.java @@ -8,7 +8,7 @@ public class TextCommandsAllTests { public static Test suite() { TestSuite suite = new TestSuite( "Test for net.rubyeye.xmemcached.test.unittest.commands.text"); - //$JUnit-BEGIN$ + // $JUnit-BEGIN$ suite.addTestSuite(TextStatsCommandUnitTest.class); suite.addTestSuite(TextIncrDecrCommandUnitTest.class); suite.addTestSuite(TextVersionCommandUnitTest.class); @@ -17,7 +17,7 @@ public static Test suite() { suite.addTestSuite(TextDeleteCommandUnitTest.class); suite.addTestSuite(TextGetOneCommandUnitTest.class); suite.addTestSuite(TextGetMultiCommandUnitTest.class); - //$JUnit-END$ + // $JUnit-END$ return suite; } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextFlushAllCommandUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextFlushAllCommandUnitTest.java index 6551eb2f1..06d55762c 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextFlushAllCommandUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextFlushAllCommandUnitTest.java @@ -7,44 +7,44 @@ public class TextFlushAllCommandUnitTest extends BaseTextCommandUnitTest { public void testEncode() { - Command command = this.commandFactory.createFlushAllCommand( - new CountDownLatch(1), 0, false); + Command command = this.commandFactory + .createFlushAllCommand(new CountDownLatch(1), 0, false); assertNull(command.getIoBuffer()); command.encode(); - assertEquals(TextFlushAllCommand.FLUSH_ALL, command.getIoBuffer() - .buf()); + assertEquals(TextFlushAllCommand.FLUSH_ALL, + command.getIoBuffer().buf()); - command = this.commandFactory.createFlushAllCommand(new CountDownLatch( - 1), 0, true); + command = this.commandFactory + .createFlushAllCommand(new CountDownLatch(1), 0, true); assertNull(command.getIoBuffer()); command.encode(); - assertEquals("flush_all noreply\r\n", new String(command.getIoBuffer() - .buf().array())); + assertEquals("flush_all noreply\r\n", + new String(command.getIoBuffer().buf().array())); } - - public void testEncodeWithDelay(){ - Command command = this.commandFactory.createFlushAllCommand( - new CountDownLatch(1), 10, false); + + public void testEncodeWithDelay() { + Command command = this.commandFactory + .createFlushAllCommand(new CountDownLatch(1), 10, false); assertNull(command.getIoBuffer()); command.encode(); - assertEquals("flush_all 10\r\n", new String(command.getIoBuffer() - .buf().array())); + assertEquals("flush_all 10\r\n", + new String(command.getIoBuffer().buf().array())); - command = this.commandFactory.createFlushAllCommand(new CountDownLatch( - 1), 10, true); + command = this.commandFactory + .createFlushAllCommand(new CountDownLatch(1), 10, true); assertNull(command.getIoBuffer()); command.encode(); - assertEquals("flush_all 10 noreply\r\n", new String(command.getIoBuffer() - .buf().array())); + assertEquals("flush_all 10 noreply\r\n", + new String(command.getIoBuffer().buf().array())); } public void testDecode() { - Command command = this.commandFactory.createFlushAllCommand( - new CountDownLatch(1), 0, false); + Command command = this.commandFactory + .createFlushAllCommand(new CountDownLatch(1), 0, false); checkDecodeNullAndNotLineByteBuffer(command); - checkDecodeInvalidLine(command,"[flush_all]", "END\r\n"); - checkDecodeInvalidLine(command,"[flush_all]", "STORED\r\n"); + checkDecodeInvalidLine(command, "[flush_all]", "END\r\n"); + checkDecodeInvalidLine(command, "[flush_all]", "STORED\r\n"); checkDecodeValidLine(command, "OK\r\n"); } } \ No newline at end of file diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextGetMultiCommandUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextGetMultiCommandUnitTest.java index b52740426..484dc7615 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextGetMultiCommandUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextGetMultiCommandUnitTest.java @@ -48,28 +48,27 @@ public void testGetManyDecode() { .createGetMultiCommand(keys, new CountDownLatch(1), CommandType.GET_MANY, transcoder); checkDecodeNullAndNotLineByteBuffer(command); - checkDecodeInvalidLine(command,"test1", "STORED\r\n"); - checkDecodeInvalidLine(command,"test1", "NOT_FOUND\r\n"); - checkDecodeInvalidLine(command,"test1", "NOT_STORED\r\n"); - checkDecodeInvalidLine(command, "test1","DELETED\r\n"); + checkDecodeInvalidLine(command, "test1", "STORED\r\n"); + checkDecodeInvalidLine(command, "test1", "NOT_FOUND\r\n"); + checkDecodeInvalidLine(command, "test1", "NOT_STORED\r\n"); + checkDecodeInvalidLine(command, "test1", "DELETED\r\n"); checkDecodeValidLine(command, "END\r\n"); assertEquals(0, ((Map) command.getResult()).size()); // data not complelte - command.setParseStatus(net.rubyeye.xmemcached.command.text.TextGetCommand.ParseStatus.NULL); - assertFalse(command.decode(null, ByteBuffer - .wrap("VALUE test1 0 2\r\n10\r\nVALUE test2 0 4\r\n10" - .getBytes()))); + command.setParseStatus( + net.rubyeye.xmemcached.command.text.TextGetCommand.ParseStatus.NULL); + assertFalse(command.decode(null, ByteBuffer.wrap( + "VALUE test1 0 2\r\n10\r\nVALUE test2 0 4\r\n10".getBytes()))); // data coming,but not with END assertFalse(command.decode(null, ByteBuffer.wrap("00\r\n".getBytes()))); checkDecodeValidLine(command, "END\r\n"); assertEquals(2, ((Map) command.getResult()).size()); - assertEquals("10", transcoder.decode(((Map) command - .getResult()).get("test1"))); - assertEquals("1000", transcoder - .decode(((Map) command.getResult()) - .get("test2"))); + assertEquals("10", transcoder.decode( + ((Map) command.getResult()).get("test1"))); + assertEquals("1000", transcoder.decode( + ((Map) command.getResult()).get("test2"))); } public void testGetsManyDecode() { @@ -77,14 +76,15 @@ public void testGetsManyDecode() { .createGetMultiCommand(keys, new CountDownLatch(1), CommandType.GETS_MANY, transcoder); checkDecodeNullAndNotLineByteBuffer(command); - checkDecodeInvalidLine(command,"test1", "STORED\r\n"); - checkDecodeInvalidLine(command,"test1", "NOT_FOUND\r\n"); - checkDecodeInvalidLine(command,"test1", "NOT_STORED\r\n"); - checkDecodeInvalidLine(command, "test1","DELETED\r\n"); + checkDecodeInvalidLine(command, "test1", "STORED\r\n"); + checkDecodeInvalidLine(command, "test1", "NOT_FOUND\r\n"); + checkDecodeInvalidLine(command, "test1", "NOT_STORED\r\n"); + checkDecodeInvalidLine(command, "test1", "DELETED\r\n"); checkDecodeValidLine(command, "END\r\n"); assertEquals(0, ((Map) command.getResult()).size()); - command.setParseStatus(net.rubyeye.xmemcached.command.text.TextGetCommand.ParseStatus.NULL); + command.setParseStatus( + net.rubyeye.xmemcached.command.text.TextGetCommand.ParseStatus.NULL); // data not complelte assertFalse(command.decode(null, ByteBuffer .wrap("VALUE test1 0 2 999\r\n10\r\nVALUE test2 0 4 1000\r\n10" @@ -94,14 +94,13 @@ public void testGetsManyDecode() { checkDecodeValidLine(command, "END\r\n"); assertEquals(2, ((Map) command.getResult()).size()); - assertEquals(999, ((Map) command.getResult()).get( - "test1").getCas()); - assertEquals(1000, ((Map) command.getResult()).get( - "test2").getCas()); - assertEquals("10", transcoder.decode(((Map) command - .getResult()).get("test1"))); - assertEquals("1000", transcoder - .decode(((Map) command.getResult()) - .get("test2"))); + assertEquals(999, ((Map) command.getResult()) + .get("test1").getCas()); + assertEquals(1000, ((Map) command.getResult()) + .get("test2").getCas()); + assertEquals("10", transcoder.decode( + ((Map) command.getResult()).get("test1"))); + assertEquals("1000", transcoder.decode( + ((Map) command.getResult()).get("test2"))); } } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextGetOneCommandUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextGetOneCommandUnitTest.java index 494269fd0..7b1132714 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextGetOneCommandUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextGetOneCommandUnitTest.java @@ -8,73 +8,73 @@ public class TextGetOneCommandUnitTest extends BaseTextCommandUnitTest { public void testGetOneEncode() { - Command command = this.commandFactory.createGetCommand("test", "test" - .getBytes(), CommandType.GET_ONE, null); + Command command = this.commandFactory.createGetCommand("test", + "test".getBytes(), CommandType.GET_ONE, null); assertNull(command.getIoBuffer()); command.encode(); checkByteBufferEquals(command, "get test\r\n"); } public void testGetsOneEncode() { - Command command = this.commandFactory.createGetCommand("test", "test" - .getBytes(), CommandType.GETS_ONE, null); + Command command = this.commandFactory.createGetCommand("test", + "test".getBytes(), CommandType.GETS_ONE, null); assertNull(command.getIoBuffer()); command.encode(); checkByteBufferEquals(command, "gets test\r\n"); } public void testGetOneDecode() { - Command command = this.commandFactory.createGetCommand("test", "test" - .getBytes(), CommandType.GET_ONE, null); + Command command = this.commandFactory.createGetCommand("test", + "test".getBytes(), CommandType.GET_ONE, null); checkDecodeNullAndNotLineByteBuffer(command); - checkDecodeInvalidLine(command,"test", "STORED\r\n"); - checkDecodeInvalidLine(command,"test", "NOT_FOUND\r\n"); - checkDecodeInvalidLine(command, "test","NOT_STORED\r\n"); - checkDecodeInvalidLine(command, "test","DELETED\r\n"); + checkDecodeInvalidLine(command, "test", "STORED\r\n"); + checkDecodeInvalidLine(command, "test", "NOT_FOUND\r\n"); + checkDecodeInvalidLine(command, "test", "NOT_STORED\r\n"); + checkDecodeInvalidLine(command, "test", "DELETED\r\n"); checkDecodeValidLine(command, "END\r\n"); assertNull(command.getResult()); assertEquals(0, command.getLatch().getCount()); - command = this.commandFactory.createGetCommand("test", "test" - .getBytes(), CommandType.GET_ONE, null); - assertFalse(command.decode(null, ByteBuffer - .wrap("VALUE test 0 2\r\n10\r\n".getBytes()))); + command = this.commandFactory.createGetCommand("test", + "test".getBytes(), CommandType.GET_ONE, null); + assertFalse(command.decode(null, + ByteBuffer.wrap("VALUE test 0 2\r\n10\r\n".getBytes()))); assertNull(command.getResult()); - assertFalse(command.decode(null, ByteBuffer.wrap("VALUE test 0 4\r\n1" - .getBytes()))); + assertFalse(command.decode(null, + ByteBuffer.wrap("VALUE test 0 4\r\n1".getBytes()))); assertFalse(command.decode(null, ByteBuffer.wrap("0".getBytes()))); assertFalse(command.decode(null, ByteBuffer.wrap("0".getBytes()))); assertFalse(command.decode(null, ByteBuffer.wrap("0".getBytes()))); checkDecodeValidLine(command, "\r\nEND\r\n"); - assertEquals("1000", new String(((CachedData) command.getResult()) - .getData())); + assertEquals("1000", + new String(((CachedData) command.getResult()).getData())); } public void testGetsOneDecode() { - Command command = this.commandFactory.createGetCommand("test", "test" - .getBytes(), CommandType.GETS_ONE, null); + Command command = this.commandFactory.createGetCommand("test", + "test".getBytes(), CommandType.GETS_ONE, null); checkDecodeNullAndNotLineByteBuffer(command); - checkDecodeInvalidLine(command, "test","STORED\r\n"); - checkDecodeInvalidLine(command, "test","NOT_FOUND\r\n"); - checkDecodeInvalidLine(command, "test","NOT_STORED\r\n"); - checkDecodeInvalidLine(command, "test","DELETED\r\n"); + checkDecodeInvalidLine(command, "test", "STORED\r\n"); + checkDecodeInvalidLine(command, "test", "NOT_FOUND\r\n"); + checkDecodeInvalidLine(command, "test", "NOT_STORED\r\n"); + checkDecodeInvalidLine(command, "test", "DELETED\r\n"); checkDecodeValidLine(command, "END\r\n"); assertNull(command.getResult()); assertEquals(0, command.getLatch().getCount()); - command = this.commandFactory.createGetCommand("test", "test" - .getBytes(), CommandType.GET_ONE, null); - assertFalse(command.decode(null, ByteBuffer - .wrap("VALUE test 0 2 999\r\n10\r\n".getBytes()))); + command = this.commandFactory.createGetCommand("test", + "test".getBytes(), CommandType.GET_ONE, null); + assertFalse(command.decode(null, + ByteBuffer.wrap("VALUE test 0 2 999\r\n10\r\n".getBytes()))); assertNull(command.getResult()); checkDecodeValidLine(command, "VALUE test 0 2 999\r\n10\r\nEND\r\n"); - assertEquals("10", new String(((CachedData) command.getResult()) - .getData())); + assertEquals("10", + new String(((CachedData) command.getResult()).getData())); assertEquals(999, ((CachedData) command.getResult()).getCas()); } } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextStatsCommandUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextStatsCommandUnitTest.java index 31d591182..a4b80d20b 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextStatsCommandUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextStatsCommandUnitTest.java @@ -26,15 +26,15 @@ public void testItemEncode() { new CountDownLatch(1), "items"); assertNull(command.getIoBuffer()); command.encode(); - assertEquals(ByteBuffer.wrap("stats items\r\n".getBytes()), command - .getIoBuffer().buf()); + assertEquals(ByteBuffer.wrap("stats items\r\n".getBytes()), + command.getIoBuffer().buf()); } public void testDecode() { Command command = this.commandFactory.createStatsCommand(null, new CountDownLatch(1), null); checkDecodeNullAndNotLineByteBuffer(command); - checkDecodeInvalidLine(command,"stats", "OK\r\n"); + checkDecodeInvalidLine(command, "stats", "OK\r\n"); checkDecodeValidLine(command, "END\r\n"); assertFalse(command.decode(null, ByteBuffer .wrap("STAT bytes 100\r\nSTAT threads 1\r\n".getBytes()))); diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextStoreCommandUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextStoreCommandUnitTest.java index e99e2e05f..8b09caac9 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextStoreCommandUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextStoreCommandUnitTest.java @@ -15,46 +15,46 @@ public class TextStoreCommandUnitTest extends BaseTextCommandUnitTest { static final Transcoder transcoder = new StringTranscoder(); public void testCASEncode() { - Command command = this.commandFactory.createCASCommand(key, key - .getBytes(), exp, value, cas, false, transcoder); + Command command = this.commandFactory.createCASCommand(key, + key.getBytes(), exp, value, cas, false, transcoder); assertNull(command.getIoBuffer()); command.encode(); checkByteBufferEquals(command, "cas test 0 0 2 999\r\n10\r\n"); - command = this.commandFactory.createCASCommand(key, key.getBytes(), - exp, value, cas, true, transcoder); + command = this.commandFactory.createCASCommand(key, key.getBytes(), exp, + value, cas, true, transcoder); command.encode(); checkByteBufferEquals(command, "cas test 0 0 2 999 noreply\r\n10\r\n"); } public void testSetEncode() { - Command command = this.commandFactory.createSetCommand(key, key - .getBytes(), exp, value, false, transcoder); + Command command = this.commandFactory.createSetCommand(key, + key.getBytes(), exp, value, false, transcoder); assertNull(command.getIoBuffer()); command.encode(); checkByteBufferEquals(command, "set test 0 0 2\r\n10\r\n"); - command = this.commandFactory.createSetCommand(key, key.getBytes(), - exp, value, true, transcoder); + command = this.commandFactory.createSetCommand(key, key.getBytes(), exp, + value, true, transcoder); command.encode(); checkByteBufferEquals(command, "set test 0 0 2 noreply\r\n10\r\n"); } public void testAddEncode() { - Command command = this.commandFactory.createAddCommand(key, key - .getBytes(), exp, value, false, transcoder); + Command command = this.commandFactory.createAddCommand(key, + key.getBytes(), exp, value, false, transcoder); assertNull(command.getIoBuffer()); command.encode(); checkByteBufferEquals(command, "add test 0 0 2\r\n10\r\n"); - command = this.commandFactory.createAddCommand(key, key.getBytes(), - exp, value, true, transcoder); + command = this.commandFactory.createAddCommand(key, key.getBytes(), exp, + value, true, transcoder); assertNull(command.getIoBuffer()); command.encode(); checkByteBufferEquals(command, "add test 0 0 2 noreply\r\n10\r\n"); } public void testReplaceEncode() { - Command command = this.commandFactory.createReplaceCommand(key, key - .getBytes(), exp, value, false, transcoder); + Command command = this.commandFactory.createReplaceCommand(key, + key.getBytes(), exp, value, false, transcoder); assertNull(command.getIoBuffer()); command.encode(); checkByteBufferEquals(command, "replace test 0 0 2\r\n10\r\n"); @@ -67,8 +67,8 @@ public void testReplaceEncode() { } public void testAppendEncode() { - Command command = this.commandFactory.createAppendCommand(key, key - .getBytes(), value, false, transcoder); + Command command = this.commandFactory.createAppendCommand(key, + key.getBytes(), value, false, transcoder); assertNull(command.getIoBuffer()); command.encode(); checkByteBufferEquals(command, "append test 0 0 2\r\n10\r\n"); @@ -81,8 +81,8 @@ public void testAppendEncode() { } public void testPrependEncode() { - Command command = this.commandFactory.createPrependCommand(key, key - .getBytes(), value, false, transcoder); + Command command = this.commandFactory.createPrependCommand(key, + key.getBytes(), value, false, transcoder); assertNull(command.getIoBuffer()); command.encode(); checkByteBufferEquals(command, "prepend test 0 0 2\r\n10\r\n"); @@ -95,11 +95,11 @@ public void testPrependEncode() { } public void testCASDecode() { - Command command = this.commandFactory.createCASCommand(key, key - .getBytes(), exp, value, cas, false, transcoder); + Command command = this.commandFactory.createCASCommand(key, + key.getBytes(), exp, value, cas, false, transcoder); checkDecodeNullAndNotLineByteBuffer(command); - checkDecodeInvalidLine(command,key, "VALUE test 4 0 5\r\n"); - checkDecodeInvalidLine(command,key, "DELETED\r\n"); + checkDecodeInvalidLine(command, key, "VALUE test 4 0 5\r\n"); + checkDecodeInvalidLine(command, key, "DELETED\r\n"); checkDecodeValidLine(command, "STORED\r\n"); assertTrue((Boolean) command.getResult()); command.setResult(null); @@ -116,32 +116,30 @@ public void testCASDecode() { public void testIssue128() { // store command - Command command = this.commandFactory.createSetCommand(key, key - .getBytes(), exp, value, false, transcoder); - command.decode(null, ByteBuffer - .wrap("SERVER_ERROR out of memory storing object\r\n" - .getBytes())); + Command command = this.commandFactory.createSetCommand(key, + key.getBytes(), exp, value, false, transcoder); + command.decode(null, ByteBuffer.wrap( + "SERVER_ERROR out of memory storing object\r\n".getBytes())); Exception e = command.getException(); assertNotNull(e); assertEquals("out of memory storing object,key=test", e.getMessage()); // cas command - command = this.commandFactory.createCASCommand(key, key.getBytes(), - exp, value, cas, false, transcoder); - command.decode(null, ByteBuffer - .wrap("SERVER_ERROR out of memory storing object\r\n" - .getBytes())); + command = this.commandFactory.createCASCommand(key, key.getBytes(), exp, + value, cas, false, transcoder); + command.decode(null, ByteBuffer.wrap( + "SERVER_ERROR out of memory storing object\r\n".getBytes())); e = command.getException(); assertNotNull(e); assertEquals("out of memory storing object,key=test", e.getMessage()); } public void testStoreDecode() { - Command command = this.commandFactory.createSetCommand(key, key - .getBytes(), exp, value, false, transcoder); + Command command = this.commandFactory.createSetCommand(key, + key.getBytes(), exp, value, false, transcoder); checkDecodeNullAndNotLineByteBuffer(command); - checkDecodeInvalidLine(command, key,"EXISTS\r\n"); - checkDecodeInvalidLine(command, key,"END\r\n"); + checkDecodeInvalidLine(command, key, "EXISTS\r\n"); + checkDecodeInvalidLine(command, key, "END\r\n"); checkDecodeValidLine(command, "STORED\r\n"); assertTrue((Boolean) command.getResult()); command.setResult(null); diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextVerbositylCommandUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextVerbositylCommandUnitTest.java index 4b57b0887..6fc52e9ce 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextVerbositylCommandUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextVerbositylCommandUnitTest.java @@ -6,27 +6,27 @@ public class TextVerbositylCommandUnitTest extends BaseTextCommandUnitTest { public void testEncode() { - Command command = this.commandFactory.createVerbosityCommand( - new CountDownLatch(1), 1, false); + Command command = this.commandFactory + .createVerbosityCommand(new CountDownLatch(1), 1, false); assertNull(command.getIoBuffer()); command.encode(); - assertEquals("verbosity 1\r\n", new String(command.getIoBuffer() - .buf().array())); + assertEquals("verbosity 1\r\n", + new String(command.getIoBuffer().buf().array())); - command = this.commandFactory.createVerbosityCommand( - new CountDownLatch(1), 1, true); + command = this.commandFactory + .createVerbosityCommand(new CountDownLatch(1), 1, true); command.encode(); - assertEquals("verbosity 1 noreply\r\n", new String(command - .getIoBuffer().buf().array())); + assertEquals("verbosity 1 noreply\r\n", + new String(command.getIoBuffer().buf().array())); } public void testDecode() { - Command command = this.commandFactory.createVerbosityCommand( - new CountDownLatch(1), 0, false); + Command command = this.commandFactory + .createVerbosityCommand(new CountDownLatch(1), 0, false); checkDecodeNullAndNotLineByteBuffer(command); - checkDecodeInvalidLine(command,"[verbosity]", "END\r\n"); - checkDecodeInvalidLine(command,"[verbosity]", "STORED\r\n"); + checkDecodeInvalidLine(command, "[verbosity]", "END\r\n"); + checkDecodeInvalidLine(command, "[verbosity]", "STORED\r\n"); checkDecodeValidLine(command, "OK\r\n"); } } \ No newline at end of file diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextVersionCommandUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextVersionCommandUnitTest.java index d10f274a6..69e9dceaf 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextVersionCommandUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/commands/text/TextVersionCommandUnitTest.java @@ -7,17 +7,19 @@ public class TextVersionCommandUnitTest extends BaseTextCommandUnitTest { public void testEncode() { - Command versionCommand = this.commandFactory.createVersionCommand(new CountDownLatch(1),null); + Command versionCommand = this.commandFactory + .createVersionCommand(new CountDownLatch(1), null); assertNull(versionCommand.getIoBuffer()); versionCommand.encode(); - assertEquals(ServerAddressAware.VERSION, versionCommand.getIoBuffer() - .buf()); + assertEquals(ServerAddressAware.VERSION, + versionCommand.getIoBuffer().buf()); } public void testDecode() { - Command versionCommand = this.commandFactory.createVersionCommand(new CountDownLatch(1),null); + Command versionCommand = this.commandFactory + .createVersionCommand(new CountDownLatch(1), null); checkDecodeNullAndNotLineByteBuffer(versionCommand); - checkDecodeInvalidLine(versionCommand, "[version]","test\r\n"); + checkDecodeInvalidLine(versionCommand, "[version]", "test\r\n"); checkDecodeValidLine(versionCommand, "VERSION\r\n"); assertEquals("unknown version", versionCommand.getResult()); diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/ArrayMemcachedSessionLocatorUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/ArrayMemcachedSessionLocatorUnitTest.java index fe4a76e24..46620370f 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/ArrayMemcachedSessionLocatorUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/ArrayMemcachedSessionLocatorUnitTest.java @@ -13,14 +13,15 @@ import com.google.code.yanf4j.core.Session; -public class ArrayMemcachedSessionLocatorUnitTest extends - AbstractMemcachedSessionLocatorUnitTest { +public class ArrayMemcachedSessionLocatorUnitTest + extends + AbstractMemcachedSessionLocatorUnitTest { @Before public void setUp() { this.locator = new ArrayMemcachedSessionLocator(); } - + @Test public void testGetSessionByKey_SessionPool() { MockSession session1 = new MockSession(8080); @@ -33,7 +34,7 @@ public void testGetSessionByKey_SessionPool() { list.add(session2); list.add(session2); list.add(session3); - + this.locator.updateSessions(list); assertSame(session2, this.locator.getSessionByKey("a")); diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/KetamaMemcachedSessionLocatorGwhalinMemcachedJavaClientUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/KetamaMemcachedSessionLocatorGwhalinMemcachedJavaClientUnitTest.java index 4cd733992..a92ef8826 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/KetamaMemcachedSessionLocatorGwhalinMemcachedJavaClientUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/KetamaMemcachedSessionLocatorGwhalinMemcachedJavaClientUnitTest.java @@ -14,12 +14,14 @@ import com.google.code.yanf4j.core.Session; -public class KetamaMemcachedSessionLocatorGwhalinMemcachedJavaClientUnitTest extends - AbstractMemcachedSessionLocatorUnitTest { +public class KetamaMemcachedSessionLocatorGwhalinMemcachedJavaClientUnitTest + extends + AbstractMemcachedSessionLocatorUnitTest { @Before public void setUp() { - this.locator = new KetamaMemcachedSessionLocator(HashAlgorithm.KETAMA_HASH, false, true); + this.locator = new KetamaMemcachedSessionLocator( + HashAlgorithm.KETAMA_HASH, false, true); } @Test @@ -27,8 +29,9 @@ public void testGetSessionByKey_MoreSessions() { MockMemcachedSession session1 = new MockMemcachedSession(8080); MockMemcachedSession session2 = new MockMemcachedSession(8081); MockMemcachedSession session3 = new MockMemcachedSession(8082); - System.err.print(session1.getInetSocketAddressWrapper().getRemoteAddressStr()); - + System.err.print( + session1.getInetSocketAddressWrapper().getRemoteAddressStr()); + List list = new ArrayList(); list.add(session1); list.add(session2); diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/KetamaMemcachedSessionLocatorNginxUpstreamConsistentUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/KetamaMemcachedSessionLocatorNginxUpstreamConsistentUnitTest.java index 60ff2e51e..00ffee682 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/KetamaMemcachedSessionLocatorNginxUpstreamConsistentUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/KetamaMemcachedSessionLocatorNginxUpstreamConsistentUnitTest.java @@ -16,7 +16,8 @@ import static org.junit.Assert.assertEquals; public class KetamaMemcachedSessionLocatorNginxUpstreamConsistentUnitTest - extends AbstractMemcachedSessionLocatorUnitTest { + extends + AbstractMemcachedSessionLocatorUnitTest { static private class MockSession implements Session { @@ -183,15 +184,17 @@ public void testSessionKey_CompatibleWithNginxUpstreamConsistent() { .getSessionByKey("127.0.0.1:11212-0").getRemoteSocketAddress()); assertEquals(session2.getRemoteSocketAddress(), this.locator .getSessionByKey("127.0.0.1:11212-1").getRemoteSocketAddress()); - assertEquals(session2.getRemoteSocketAddress(), this.locator - .getSessionByKey("127.0.0.1:11212-39").getRemoteSocketAddress()); + assertEquals(session2.getRemoteSocketAddress(), + this.locator.getSessionByKey("127.0.0.1:11212-39") + .getRemoteSocketAddress()); assertEquals(session3.getRemoteSocketAddress(), this.locator .getSessionByKey("127.0.0.1:11213-0").getRemoteSocketAddress()); assertEquals(session3.getRemoteSocketAddress(), this.locator .getSessionByKey("127.0.0.1:11213-1").getRemoteSocketAddress()); - assertEquals(session3.getRemoteSocketAddress(), this.locator - .getSessionByKey("127.0.0.1:11213-39").getRemoteSocketAddress()); + assertEquals(session3.getRemoteSocketAddress(), + this.locator.getSessionByKey("127.0.0.1:11213-39") + .getRemoteSocketAddress()); } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/KetamaMemcachedSessionLocatorUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/KetamaMemcachedSessionLocatorUnitTest.java index d02ba0fb0..fbc109ceb 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/KetamaMemcachedSessionLocatorUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/KetamaMemcachedSessionLocatorUnitTest.java @@ -13,8 +13,9 @@ import com.google.code.yanf4j.core.Session; -public class KetamaMemcachedSessionLocatorUnitTest extends - AbstractMemcachedSessionLocatorUnitTest { +public class KetamaMemcachedSessionLocatorUnitTest + extends + AbstractMemcachedSessionLocatorUnitTest { @Before public void setUp() { diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/MemcachedClientStateListenerIT.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/MemcachedClientStateListenerIT.java index 0629eddda..63e6d3d42 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/MemcachedClientStateListenerIT.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/MemcachedClientStateListenerIT.java @@ -63,8 +63,8 @@ public void testConnected() throws Exception { while (memcachedClient.getAvaliableServers().size() < list.size()) wait(1000); } - assertEquals(1 + memcachedClient.getAvaliableServers().size(), listener - .getNum()); + assertEquals(1 + memcachedClient.getAvaliableServers().size(), + listener.getNum()); } public void testDisconnected() throws Exception { @@ -81,9 +81,9 @@ public void testDisconnected() throws Exception { Thread.sleep(2000); memcachedClient.shutdown(); synchronized (this) { - - while (memcachedClient.getAvaliableServers().size() > 0){ - //System.out.println(memcachedClient.getAvaliableServers().size()); + + while (memcachedClient.getAvaliableServers().size() > 0) { + // System.out.println(memcachedClient.getAvaliableServers().size()); wait(1000); } } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/MemcachedHandlerUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/MemcachedHandlerUnitTest.java index 13a9e20df..75f5817cf 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/MemcachedHandlerUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/MemcachedHandlerUnitTest.java @@ -51,8 +51,8 @@ public void testOnMessageSent_TextCommand() { @Test public void testOnMessageSent_TextCommand_NoReply() { - TextStoreCommand cmd = new TextStoreCommand(null, null, - CommandType.SET, null, 1, 1, "hello", true, null); + TextStoreCommand cmd = new TextStoreCommand(null, null, CommandType.SET, + null, 1, 1, "hello", true, null); Assert.assertEquals("hello", cmd.getValue()); this.mocksControl.replay(); this.handler.onMessageSent(this.session, cmd); diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/MemcachedSessionComparatorUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/MemcachedSessionComparatorUnitTest.java index 152f9537e..9121213e1 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/MemcachedSessionComparatorUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/MemcachedSessionComparatorUnitTest.java @@ -44,7 +44,7 @@ public boolean isAuthFailed() { public void setAuthFailed(boolean authFailed) { // TODO Auto-generated method stub - + } public Future asyncWrite(Object packet) { diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/MockMemcachedClientStateListener.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/MockMemcachedClientStateListener.java index 0fb4b711c..11531b868 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/MockMemcachedClientStateListener.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/MockMemcachedClientStateListener.java @@ -6,15 +6,15 @@ import net.rubyeye.xmemcached.MemcachedClient; import net.rubyeye.xmemcached.MemcachedClientStateListener; -public class MockMemcachedClientStateListener implements - MemcachedClientStateListener { +public class MockMemcachedClientStateListener + implements + MemcachedClientStateListener { AtomicInteger num; public MockMemcachedClientStateListener() { this.num = new AtomicInteger(0); } - public void onConnected(MemcachedClient memcachedClient, InetSocketAddress inetSocketAddress) { this.num.incrementAndGet(); @@ -22,7 +22,6 @@ public void onConnected(MemcachedClient memcachedClient, + ":" + inetSocketAddress.getPort()); } - public void onDisconnected(MemcachedClient memcachedClient, InetSocketAddress inetSocketAddress) { this.num.incrementAndGet(); @@ -30,8 +29,8 @@ public void onDisconnected(MemcachedClient memcachedClient, + ":" + inetSocketAddress.getPort()); } - - public void onException(MemcachedClient memcachedClient, Throwable throwable) { + public void onException(MemcachedClient memcachedClient, + Throwable throwable) { this.num.incrementAndGet(); System.out.println("Client onException"); @@ -41,14 +40,12 @@ public int getNum() { return this.num.get(); } - public void onShutDown(MemcachedClient memcachedClient) { this.num.incrementAndGet(); System.out.println("Client shutdown"); } - public void onStarted(MemcachedClient memcachedClient) { this.num.incrementAndGet(); System.out.println("Client started"); diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/OptimizerTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/OptimizerTest.java index 9fbff8444..38b2aa299 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/OptimizerTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/OptimizerTest.java @@ -74,7 +74,8 @@ public void testOptimiezeSetLimitBuffer() { int limit = 100; BinarySetMultiCommand optimiezedCommand = (BinarySetMultiCommand) this.optimiezer - .optimiezeSet(this.writeQueue, this.executingCmds, this.currentCmd, limit); + .optimiezeSet(this.writeQueue, this.executingCmds, + this.currentCmd, limit); assertEquals(optimiezedCommand.getMergeCount(), Math.round((double) limit / oneBufferSize)); } @@ -97,8 +98,8 @@ public void testOptimiezeSetAllBuffers() { this.currentCmd.encode(); BinarySetMultiCommand optimiezedCommand = (BinarySetMultiCommand) this.optimiezer - .optimiezeSet(this.writeQueue, this.executingCmds, this.currentCmd, - Integer.MAX_VALUE); + .optimiezeSet(this.writeQueue, this.executingCmds, + this.currentCmd, Integer.MAX_VALUE); assertEquals(optimiezedCommand.getMergeCount(), 10); } @@ -114,8 +115,8 @@ public void testOptimiezeGet() { assertNull(this.writeQueue.peek()); assertSame(CommandType.GET_ONE, optimiezeCommand.getCommandType()); assertEquals(10, optimiezeCommand.getMergeCount()); - assertEquals("get 0 1 2 3 4 5 6 7 8 9\r\n", new String(optimiezeCommand - .getIoBuffer().buf().array())); + assertEquals("get 0 1 2 3 4 5 6 7 8 9\r\n", + new String(optimiezeCommand.getIoBuffer().buf().array())); } public void testOptimiezeGetWithSameKey() { @@ -140,8 +141,8 @@ public void testOptimiezeGetWithSameKey() { assertNull(this.writeQueue.peek()); assertSame(CommandType.GET_ONE, optimiezeCommand.getCommandType()); assertEquals(11, optimiezeCommand.getMergeCount()); - assertEquals("get 0\r\n", new String(optimiezeCommand.getIoBuffer() - .buf().array())); + assertEquals("get 0\r\n", + new String(optimiezeCommand.getIoBuffer().buf().array())); optimiezeCommand.decode(null, ByteBuffer.wrap("VALUE 0 0 2\r\n10\r\n".getBytes())); @@ -151,8 +152,8 @@ public void testOptimiezeGetWithSameKey() { transcoder.decode((CachedData) this.currentCmd.getResult())); for (Command cmd : localQueue) { assertEquals(0, cmd.getLatch().getCount()); - assertEquals("10", - transcoder.decode((CachedData) this.currentCmd.getResult())); + assertEquals("10", transcoder + .decode((CachedData) this.currentCmd.getResult())); } assertEquals(0, optimiezeCommand.getMergeCount()); } @@ -166,8 +167,8 @@ public void testMergeFactorDecrease() { assertEquals(5, optimiezeCommand.getMergeCommands().size()); assertSame(CommandType.GET_ONE, optimiezeCommand.getCommandType()); assertEquals(5, optimiezeCommand.getMergeCount()); - assertEquals("get 0 1 2 3 4\r\n", new String(optimiezeCommand - .getIoBuffer().buf().array())); + assertEquals("get 0 1 2 3 4\r\n", + new String(optimiezeCommand.getIoBuffer().buf().array())); assertEquals(5, this.writeQueue.size()); // remain five commands } @@ -182,8 +183,8 @@ public void testMergeFactorEqualsZero() { assertSame(CommandType.GET_ONE, optimiezeCommand.getCommandType()); assertNull(optimiezeCommand.getMergeCommands()); assertEquals(-1, optimiezeCommand.getMergeCount()); - assertEquals("get 0\r\n", new String(optimiezeCommand.getIoBuffer() - .buf().array())); + assertEquals("get 0\r\n", + new String(optimiezeCommand.getIoBuffer().buf().array())); assertEquals(9, this.writeQueue.size()); assertSame(this.currentCmd, optimiezeCommand); } @@ -198,8 +199,8 @@ public void testDisableMergeGet() { assertSame(CommandType.GET_ONE, optimiezeCommand.getCommandType()); assertNull(optimiezeCommand.getMergeCommands()); assertEquals(-1, optimiezeCommand.getMergeCount()); - assertEquals("get 0\r\n", new String(optimiezeCommand.getIoBuffer() - .buf().array())); + assertEquals("get 0\r\n", + new String(optimiezeCommand.getIoBuffer().buf().array())); assertEquals(9, this.writeQueue.size()); assertSame(this.currentCmd, optimiezeCommand); } @@ -230,16 +231,16 @@ public void testMergeDifferenceCommands() { assertEquals(5, optimiezeCommand.getMergeCommands().size()); assertSame(CommandType.GET_ONE, optimiezeCommand.getCommandType()); assertEquals(6, optimiezeCommand.getMergeCount()); - assertEquals("get 0 1 2 3 4\r\n", new String(optimiezeCommand - .getIoBuffer().buf().array())); + assertEquals("get 0 1 2 3 4\r\n", + new String(optimiezeCommand.getIoBuffer().buf().array())); assertEquals(5, this.writeQueue.size()); // remain five commands } public void testMergeGetCommandsWithEmptyWriteQueue() { this.writeQueue.clear(); - Command optimiezeCommand = this.optimiezer.optimiezeGet( - this.writeQueue, this.executingCmds, this.currentCmd); + Command optimiezeCommand = this.optimiezer.optimiezeGet(this.writeQueue, + this.executingCmds, this.currentCmd); optimiezeCommand.encode(); ByteBuffer mergeBuffer = optimiezeCommand.getIoBuffer().buf(); assertSame(this.currentCmd, optimiezeCommand); @@ -259,8 +260,8 @@ public void testMergeLimitBuffer() { ByteBuffer mergeBuffer = optimiezeCommand.getIoBuffer().buf(); assertEquals(0, this.writeQueue.size()); assertSame(CommandType.GET_ONE, optimiezeCommand.getCommandType()); - assertEquals("get 0\r\nget 1 2 3 4 5 6 7 8 9\r\n", new String( - mergeBuffer.array())); // current command at last + assertEquals("get 0\r\nget 1 2 3 4 5 6 7 8 9\r\n", + new String(mergeBuffer.array())); // current command at last } public void testMergeAllBuffer() { @@ -272,8 +273,8 @@ public void testMergeAllBuffer() { assertNotSame(this.currentCmd, optimiezeCommand); assertTrue(mergeBuffer.remaining() < 100); assertEquals(0, this.writeQueue.size()); - assertEquals("get 0\r\nget 1 2 3 4 5 6 7 8 9\r\n", new String( - mergeBuffer.array())); // current command at last + assertEquals("get 0\r\nget 1 2 3 4 5 6 7 8 9\r\n", + new String(mergeBuffer.array())); // current command at last } public void testMergeBufferWithEmptyWriteQueue() { diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/RoundRobinMemcachedSessionLocatorUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/RoundRobinMemcachedSessionLocatorUnitTest.java index c3165e584..8a2f842f2 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/RoundRobinMemcachedSessionLocatorUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/RoundRobinMemcachedSessionLocatorUnitTest.java @@ -14,8 +14,9 @@ import com.google.code.yanf4j.core.Session; -public class RoundRobinMemcachedSessionLocatorUnitTest extends - AbstractMemcachedSessionLocatorUnitTest { +public class RoundRobinMemcachedSessionLocatorUnitTest + extends + AbstractMemcachedSessionLocatorUnitTest { @Before public void setUp() { this.locator = new RoundRobinMemcachedSessionLocator(); diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/SessionLocatorTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/SessionLocatorTest.java index 611ba4325..2ebee0034 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/SessionLocatorTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/impl/SessionLocatorTest.java @@ -38,8 +38,8 @@ public void testArraySessionLocator() { oldSession.close(); assertNotSame(oldSession, sessionLocator.getSessionByKey(key)); // use next - assertSame(sessions.get(oldIndex + 1), sessionLocator - .getSessionByKey(key)); + assertSame(sessions.get(oldIndex + 1), + sessionLocator.getSessionByKey(key)); sessions = new ArrayList(); sessionLocator.updateSessions(sessions); assertNull(sessionLocator.getSessionByKey(key)); diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/mock/MockDecodeTimeoutBinaryGetOneCommand.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/mock/MockDecodeTimeoutBinaryGetOneCommand.java index f023c6e69..7cbd83d77 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/mock/MockDecodeTimeoutBinaryGetOneCommand.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/mock/MockDecodeTimeoutBinaryGetOneCommand.java @@ -15,12 +15,12 @@ public MockDecodeTimeoutBinaryGetOneCommand(String key, byte[] keyBytes, CommandType cmdType, CountDownLatch latch, OpCode opCode, boolean noreply, long sleepTime) { super(key, keyBytes, cmdType, latch, opCode, noreply); - this.sleepTime=sleepTime; + this.sleepTime = sleepTime; // TODO Auto-generated constructor stub } @Override - public boolean decode(MemcachedTCPSession session, ByteBuffer buffer){ + public boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { // TODO Auto-generated method stub try { Thread.sleep(this.sleepTime); diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/mock/MockEncodeTimeoutBinaryGetCommand.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/mock/MockEncodeTimeoutBinaryGetCommand.java index 9547d5824..e33e5fdc3 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/mock/MockEncodeTimeoutBinaryGetCommand.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/mock/MockEncodeTimeoutBinaryGetCommand.java @@ -13,7 +13,7 @@ public MockEncodeTimeoutBinaryGetCommand(String key, byte[] keyBytes, CommandType cmdType, CountDownLatch latch, OpCode opCode, boolean noreply, long sleepTime) { super(key, keyBytes, cmdType, latch, opCode, noreply); - this.sleepTime=sleepTime; + this.sleepTime = sleepTime; } @Override diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/mock/MockErrorBinaryGetOneCommand.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/mock/MockErrorBinaryGetOneCommand.java index adbc420c9..f748c42a5 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/mock/MockErrorBinaryGetOneCommand.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/mock/MockErrorBinaryGetOneCommand.java @@ -6,8 +6,9 @@ import net.rubyeye.xmemcached.command.binary.BinaryGetCommand; import net.rubyeye.xmemcached.command.binary.OpCode; -public class MockErrorBinaryGetOneCommand extends BinaryGetCommand implements - MockErrorCommand { +public class MockErrorBinaryGetOneCommand extends BinaryGetCommand + implements + MockErrorCommand { private boolean decode; @@ -18,18 +19,14 @@ public MockErrorBinaryGetOneCommand(String key, byte[] keyBytes, // TODO Auto-generated constructor stub } - - @Override protected boolean finish() { - this.decode=true; + this.decode = true; super.finish(); decodeError(); return true; } - - public boolean isDecoded() { return this.decode; } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/mock/MockErrorTextGetOneCommand.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/mock/MockErrorTextGetOneCommand.java index 258c70beb..217199b54 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/mock/MockErrorTextGetOneCommand.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/mock/MockErrorTextGetOneCommand.java @@ -5,7 +5,9 @@ import net.rubyeye.xmemcached.command.CommandType; import net.rubyeye.xmemcached.command.text.TextGetOneCommand; -public class MockErrorTextGetOneCommand extends TextGetOneCommand implements MockErrorCommand{ +public class MockErrorTextGetOneCommand extends TextGetOneCommand + implements + MockErrorCommand { private volatile boolean decoded; diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/monitor/Mock.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/monitor/Mock.java index 20b801734..10b9fdfbf 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/monitor/Mock.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/monitor/Mock.java @@ -2,7 +2,6 @@ public class Mock implements MockMBean { - public String say(String name) { return "hello," + name; } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/monitor/XMemcachedMBeanServerUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/monitor/XMemcachedMBeanServerUnitTest.java index 5a27badd7..a042e841d 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/monitor/XMemcachedMBeanServerUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/monitor/XMemcachedMBeanServerUnitTest.java @@ -16,7 +16,7 @@ public void setUp() { public void testMBeanServer() throws Exception { Method method = XMemcachedMbeanServer.getInstance().getClass() - .getDeclaredMethod("initialize", new Class[] {}); + .getDeclaredMethod("initialize", new Class[]{}); method.setAccessible(true); method.invoke(XMemcachedMbeanServer.getInstance()); @@ -25,8 +25,8 @@ public void testMBeanServer() throws Exception { String name = mock.getClass().getPackage().getName() + ":type=" + mock.getClass().getSimpleName(); XMemcachedMbeanServer.getInstance().registMBean(mock, name); - assertEquals(oldCount + 1, XMemcachedMbeanServer.getInstance() - .getMBeanCount()); + assertEquals(oldCount + 1, + XMemcachedMbeanServer.getInstance().getMBeanCount()); assertTrue(XMemcachedMbeanServer.getInstance().isRegistered(name)); XMemcachedMbeanServer.getInstance().shutdown(); assertFalse(XMemcachedMbeanServer.getInstance().isActive()); diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/BaseSerializingTranscoderTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/BaseSerializingTranscoderTest.java index d36e07d2f..b9f34001e 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/BaseSerializingTranscoderTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/BaseSerializingTranscoderTest.java @@ -71,14 +71,14 @@ public void testDecompressNull() { } public void testUndeserializable() throws Exception { - byte[] data = { -84, -19, 0, 5, 115, 114, 0, 4, 84, 101, 115, 116, 2, - 61, 102, -87, -28, 17, 52, 30, 2, 0, 1, 73, 0, 9, 115, 111, - 109, 101, 116, 104, 105, 110, 103, 120, 112, 0, 0, 0, 5 }; + byte[] data = {-84, -19, 0, 5, 115, 114, 0, 4, 84, 101, 115, 116, 2, 61, + 102, -87, -28, 17, 52, 30, 2, 0, 1, 73, 0, 9, 115, 111, 109, + 101, 116, 104, 105, 110, 103, 120, 112, 0, 0, 0, 5}; assertNull(ex.deserialize(data)); } public void testDeserializable() throws Exception { - byte[] data = { -84, -19, 0, 5, 116, 0, 5, 104, 101, 108, 108, 111 }; + byte[] data = {-84, -19, 0, 5, 116, 0, 5, 104, 101, 108, 108, 111}; assertEquals("hello", ex.deserialize(data)); } @@ -88,8 +88,8 @@ public void testBadCharsetDecode() { ex.encodeString("Woo!"); fail("Expected runtime exception"); } catch (RuntimeException e) { - assertSame(UnsupportedEncodingException.class, e.getCause() - .getClass()); + assertSame(UnsupportedEncodingException.class, + e.getCause().getClass()); } } @@ -99,8 +99,8 @@ public void testBadCharsetEncode() { ex.decodeString("Woo!".getBytes()); fail("Expected runtime exception"); } catch (RuntimeException e) { - assertSame(UnsupportedEncodingException.class, e.getCause() - .getClass()); + assertSame(UnsupportedEncodingException.class, + e.getCause().getClass()); } } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/BaseTranscoderCase.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/BaseTranscoderCase.java index d0481db65..f441d0ff8 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/BaseTranscoderCase.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/BaseTranscoderCase.java @@ -9,8 +9,6 @@ import net.rubyeye.xmemcached.transcoders.CachedData; import net.rubyeye.xmemcached.transcoders.Transcoder; - - /** * Basic behavior validation for all transcoders that work with objects. */ @@ -20,7 +18,7 @@ public abstract class BaseTranscoderCase extends TestCase { protected void setTranscoder(Transcoder t) { assert t != null; - this.tc=t; + this.tc = t; } protected Transcoder getTranscoder() { @@ -28,17 +26,17 @@ protected Transcoder getTranscoder() { } public void testSomethingBigger() throws Exception { - Collection dates=new ArrayList(); - for(int i=0; i<1024; i++) { + Collection dates = new ArrayList(); + for (int i = 0; i < 1024; i++) { dates.add(new Date()); } - CachedData d=this.tc.encode(dates); + CachedData d = this.tc.encode(dates); assertEquals(dates, this.tc.decode(d)); } public void testDate() throws Exception { - Date d=new Date(); - CachedData cd=this.tc.encode(d); + Date d = new Date(); + CachedData cd = this.tc.encode(d); assertEquals(d, this.tc.decode(cd)); } @@ -51,7 +49,7 @@ public void testInt() throws Exception { } public void testShort() throws Exception { - assertEquals((short)923, this.tc.decode(this.tc.encode((short)923))); + assertEquals((short) 923, this.tc.decode(this.tc.encode((short) 923))); } public void testChar() throws Exception { @@ -64,7 +62,7 @@ public void testBoolean() throws Exception { } public void testByte() throws Exception { - assertEquals((byte)-127, this.tc.decode(this.tc.encode((byte)-127))); + assertEquals((byte) -127, this.tc.decode(this.tc.encode((byte) -127))); } public void testCharacter() throws Exception { @@ -72,18 +70,17 @@ public void testCharacter() throws Exception { } public void testStringBuilder() throws Exception { - StringBuilder sb=new StringBuilder("test"); - StringBuilder sb2=(StringBuilder)this.tc.decode(this.tc.encode(sb)); + StringBuilder sb = new StringBuilder("test"); + StringBuilder sb2 = (StringBuilder) this.tc.decode(this.tc.encode(sb)); assertEquals(sb.toString(), sb2.toString()); } public void testStringBuffer() throws Exception { - StringBuffer sb=new StringBuffer("test"); - StringBuffer sb2=(StringBuffer)this.tc.decode(this.tc.encode(sb)); + StringBuffer sb = new StringBuffer("test"); + StringBuffer sb2 = (StringBuffer) this.tc.decode(this.tc.encode(sb)); assertEquals(sb.toString(), sb2.toString()); } - private void assertFloat(float f) { assertEquals(f, this.tc.decode(this.tc.encode(f))); } @@ -115,20 +112,16 @@ public void testDouble() throws Exception { } private void assertLong(long l) { - CachedData encoded=this.tc.encode(l); - long decoded=(Long)this.tc.decode(encoded); + CachedData encoded = this.tc.encode(l); + long decoded = (Long) this.tc.decode(encoded); assertEquals(l, decoded); } /* - private void displayBytes(long l, byte[] encoded) { - System.out.print(l + " ["); - for(byte b : encoded) { - System.out.print((b<0?256+b:b) + " "); - } - System.out.println("]"); - } - */ + * private void displayBytes(long l, byte[] encoded) { System.out.print(l + + * " ["); for(byte b : encoded) { System.out.print((b<0?256+b:b) + " "); } + * System.out.println("]"); } + */ public void testLongEncoding() throws Exception { assertLong(Long.MIN_VALUE); @@ -141,8 +134,8 @@ public void testLongEncoding() throws Exception { } private void assertInt(int i) { - CachedData encoded=this.tc.encode(i); - int decoded=(Integer)this.tc.decode(encoded); + CachedData encoded = this.tc.encode(i); + int decoded = (Integer) this.tc.decode(encoded); assertEquals(i, decoded); } @@ -157,29 +150,29 @@ public void testIntEncoding() throws Exception { } public void testBooleanEncoding() throws Exception { - assertTrue((Boolean)this.tc.decode(this.tc.encode(true))); - assertFalse((Boolean)this.tc.decode(this.tc.encode(false))); + assertTrue((Boolean) this.tc.decode(this.tc.encode(true))); + assertFalse((Boolean) this.tc.decode(this.tc.encode(false))); } public void testByteArray() throws Exception { - byte[] a={'a', 'b', 'c'}; - CachedData cd=this.tc.encode(a); + byte[] a = {'a', 'b', 'c'}; + CachedData cd = this.tc.encode(a); assertTrue(Arrays.equals(a, cd.getData())); - assertTrue(Arrays.equals(a, (byte[])this.tc.decode(cd))); + assertTrue(Arrays.equals(a, (byte[]) this.tc.decode(cd))); } public void testStrings() throws Exception { - String s1="This is a simple test string."; - CachedData cd=this.tc.encode(s1); + String s1 = "This is a simple test string."; + CachedData cd = this.tc.encode(s1); assertEquals(getStringFlags(), cd.getFlag()); assertEquals(s1, this.tc.decode(cd)); } public void testUTF8String() throws Exception { - String s1="\u2013\u00f3\u2013\u00a5\u2014\u00c4\u2013\u221e\u2013" - + "\u2264\u2014\u00c5\u2014\u00c7\u2013\u2264\u2014\u00c9\u2013" - + "\u03c0, \u2013\u00ba\u2013\u220f\u2014\u00c4."; - CachedData cd=this.tc.encode(s1); + String s1 = "\u2013\u00f3\u2013\u00a5\u2014\u00c4\u2013\u221e\u2013" + + "\u2264\u2014\u00c5\u2014\u00c7\u2013\u2264\u2014\u00c9\u2013" + + "\u03c0, \u2013\u00ba\u2013\u220f\u2014\u00c4."; + CachedData cd = this.tc.encode(s1); assertEquals(getStringFlags(), cd.getFlag()); assertEquals(s1, this.tc.decode(cd)); } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/CachedDataTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/CachedDataTest.java index 74cecf50c..cd37b46d6 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/CachedDataTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/CachedDataTest.java @@ -9,12 +9,12 @@ public class CachedDataTest extends TestCase { public void testToString() throws Exception { - String exp="{CachedData flags=13 data=[84, 104, 105, 115, 32, 105, " - + "115, 32, 97, 32, 115, 105, 109, 112, 108, 101, 32, 116, 101, " - + "115, 116, 32, 115, 116, 114, 105, 110, 103, 46]}"; - CachedData cd=new CachedData(13, - "This is a simple test string.".getBytes("UTF-8"), - CachedData.MAX_SIZE,-1); + String exp = "{CachedData flags=13 data=[84, 104, 105, 115, 32, 105, " + + "115, 32, 97, 32, 115, 105, 109, 112, 108, 101, 32, 116, 101, " + + "115, 116, 32, 115, 116, 114, 105, 110, 103, 46]}"; + CachedData cd = new CachedData(13, + "This is a simple test string.".getBytes("UTF-8"), + CachedData.MAX_SIZE, -1); assertEquals(exp, String.valueOf(cd)); } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/IntegerTranscoderTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/IntegerTranscoderTest.java index 95484266f..b62093d66 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/IntegerTranscoderTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/IntegerTranscoderTest.java @@ -9,12 +9,12 @@ */ public class IntegerTranscoderTest extends TestCase { - private IntegerTranscoder tc=null; + private IntegerTranscoder tc = null; @Override protected void setUp() throws Exception { super.setUp(); - tc=new IntegerTranscoder(); + tc = new IntegerTranscoder(); } public void testInt() throws Exception { @@ -22,8 +22,8 @@ public void testInt() throws Exception { } public void testBadFlags() throws Exception { - CachedData cd=tc.encode(9284); - assertNull(tc.decode(new CachedData(cd.getFlag()+1, cd.getData(), - CachedData.MAX_SIZE,-1))); + CachedData cd = tc.encode(9284); + assertNull(tc.decode(new CachedData(cd.getFlag() + 1, cd.getData(), + CachedData.MAX_SIZE, -1))); } } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/LongTranscoderTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/LongTranscoderTest.java index 2bfa6db11..06ac55932 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/LongTranscoderTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/LongTranscoderTest.java @@ -9,12 +9,12 @@ */ public class LongTranscoderTest extends TestCase { - private LongTranscoder tc=null; + private LongTranscoder tc = null; @Override protected void setUp() throws Exception { super.setUp(); - tc=new LongTranscoder(); + tc = new LongTranscoder(); } public void testLong() throws Exception { @@ -22,8 +22,8 @@ public void testLong() throws Exception { } public void testBadFlags() throws Exception { - CachedData cd=tc.encode(9284L); - assertNull(tc.decode(new CachedData(cd.getFlag()+1, cd.getData(), - CachedData.MAX_SIZE,-1))); + CachedData cd = tc.encode(9284L); + assertNull(tc.decode(new CachedData(cd.getFlag() + 1, cd.getData(), + CachedData.MAX_SIZE, -1))); } } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/PrimitiveAsStringUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/PrimitiveAsStringUnitTest.java index fee52cc23..86f17c930 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/PrimitiveAsStringUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/PrimitiveAsStringUnitTest.java @@ -30,79 +30,73 @@ public void setUp() { public void testXmemcachedTranscoderEncode() { - Assert.assertEquals(this.str, encodeAndGet(this.str, - this.serializingTranscoder)); - Assert.assertEquals("1", encodeAndGet(this.i, - this.serializingTranscoder)); - Assert.assertEquals("2", encodeAndGet(this.b, - this.serializingTranscoder)); - Assert.assertEquals("34930403040", encodeAndGet(this.l, - this.serializingTranscoder)); - Assert.assertEquals("1.02", encodeAndGet(this.f, - this.serializingTranscoder)); - Assert.assertEquals("3.14", encodeAndGet(this.d, - this.serializingTranscoder)); -// Assert.assertEquals("1024", encodeAndGet(this.s, -// this.serializingTranscoder)); + Assert.assertEquals(this.str, + encodeAndGet(this.str, this.serializingTranscoder)); + Assert.assertEquals("1", + encodeAndGet(this.i, this.serializingTranscoder)); + Assert.assertEquals("2", + encodeAndGet(this.b, this.serializingTranscoder)); + Assert.assertEquals("34930403040", + encodeAndGet(this.l, this.serializingTranscoder)); + Assert.assertEquals("1.02", + encodeAndGet(this.f, this.serializingTranscoder)); + Assert.assertEquals("3.14", + encodeAndGet(this.d, this.serializingTranscoder)); + // Assert.assertEquals("1024", encodeAndGet(this.s, + // this.serializingTranscoder)); } public void testXmemcachedDecode() { - Assert.assertEquals(this.str, decodeAndGet(this.str, - this.serializingTranscoder)); - Assert.assertEquals("1", decodeAndGet(this.i, - this.serializingTranscoder)); - Assert.assertEquals("2", decodeAndGet(this.b, - this.serializingTranscoder)); - Assert.assertEquals("34930403040", decodeAndGet(this.l, - this.serializingTranscoder)); - Assert.assertEquals("1.02", decodeAndGet(this.f, - this.serializingTranscoder)); - Assert.assertEquals("3.14", decodeAndGet(this.d, - this.serializingTranscoder)); - Assert.assertEquals(this.s, decodeAndGet(this.s, - this.serializingTranscoder)); - Assert.assertEquals(this.map, decodeAndGet(this.map, - this.serializingTranscoder)); + Assert.assertEquals(this.str, + decodeAndGet(this.str, this.serializingTranscoder)); + Assert.assertEquals("1", + decodeAndGet(this.i, this.serializingTranscoder)); + Assert.assertEquals("2", + decodeAndGet(this.b, this.serializingTranscoder)); + Assert.assertEquals("34930403040", + decodeAndGet(this.l, this.serializingTranscoder)); + Assert.assertEquals("1.02", + decodeAndGet(this.f, this.serializingTranscoder)); + Assert.assertEquals("3.14", + decodeAndGet(this.d, this.serializingTranscoder)); + Assert.assertEquals(this.s, + decodeAndGet(this.s, this.serializingTranscoder)); + Assert.assertEquals(this.map, + decodeAndGet(this.map, this.serializingTranscoder)); } public void testWhalinTranscoderTranscoderEncode() { - Assert.assertEquals(this.str, encodeAndGet(this.str, - this.whalinTranscoder)); + Assert.assertEquals(this.str, + encodeAndGet(this.str, this.whalinTranscoder)); Assert.assertEquals("1", encodeAndGet(this.i, this.whalinTranscoder)); Assert.assertEquals("2", encodeAndGet(this.b, this.whalinTranscoder)); - Assert.assertEquals("34930403040", encodeAndGet(this.l, - this.whalinTranscoder)); - Assert - .assertEquals("1.02", encodeAndGet(this.f, - this.whalinTranscoder)); - Assert - .assertEquals("3.14", encodeAndGet(this.d, - this.whalinTranscoder)); - Assert - .assertEquals("1024", encodeAndGet(this.s, - this.whalinTranscoder)); + Assert.assertEquals("34930403040", + encodeAndGet(this.l, this.whalinTranscoder)); + Assert.assertEquals("1.02", + encodeAndGet(this.f, this.whalinTranscoder)); + Assert.assertEquals("3.14", + encodeAndGet(this.d, this.whalinTranscoder)); + Assert.assertEquals("1024", + encodeAndGet(this.s, this.whalinTranscoder)); } public void testWhalinTranscoderDecode() { - Assert.assertEquals(this.str, decodeAndGet(this.str, - this.whalinTranscoder)); + Assert.assertEquals(this.str, + decodeAndGet(this.str, this.whalinTranscoder)); Assert.assertEquals("1", decodeAndGet(this.i, this.whalinTranscoder)); Assert.assertEquals("2", decodeAndGet(this.b, this.whalinTranscoder)); - Assert.assertEquals("34930403040", decodeAndGet(this.l, - this.whalinTranscoder)); - Assert - .assertEquals("1.02", decodeAndGet(this.f, - this.whalinTranscoder)); - Assert - .assertEquals("3.14", decodeAndGet(this.d, - this.whalinTranscoder)); - Assert - .assertEquals("1024", decodeAndGet(this.s, - this.whalinTranscoder)); - Assert.assertEquals(this.map, decodeAndGet(this.map, - this.whalinTranscoder)); + Assert.assertEquals("34930403040", + decodeAndGet(this.l, this.whalinTranscoder)); + Assert.assertEquals("1.02", + decodeAndGet(this.f, this.whalinTranscoder)); + Assert.assertEquals("3.14", + decodeAndGet(this.d, this.whalinTranscoder)); + Assert.assertEquals("1024", + decodeAndGet(this.s, this.whalinTranscoder)); + Assert.assertEquals(this.map, + decodeAndGet(this.map, this.whalinTranscoder)); } private Object decodeAndGet(Object obj, Transcoder transcoder) { diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/SerializingTranscoderTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/SerializingTranscoderTest.java index aa4063744..2b2f67427 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/SerializingTranscoderTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/SerializingTranscoderTest.java @@ -94,8 +94,8 @@ public void testUnencodeable() throws Exception { public void testUndecodeable() throws Exception { CachedData cd = new CachedData( - Integer.MAX_VALUE - & ~(SerializingTranscoder.COMPRESSED | SerializingTranscoder.SERIALIZED), + Integer.MAX_VALUE & ~(SerializingTranscoder.COMPRESSED + | SerializingTranscoder.SERIALIZED), tu.encodeInt(Integer.MAX_VALUE), tc.getMaxSize(), -1); assertNull(tc.decode(cd)); } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/TokyoTyrantTranscoderUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/TokyoTyrantTranscoderUnitTest.java index da981cef1..3bcb4d114 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/TokyoTyrantTranscoderUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/TokyoTyrantTranscoderUnitTest.java @@ -12,7 +12,7 @@ public class TokyoTyrantTranscoderUnitTest extends TestCase { TokyoTyrantTranscoder tokyoTyrantTranscoder; public void setUp() { - tokyoTyrantTranscoder = new TokyoTyrantTranscoder(5*1024*1024); + tokyoTyrantTranscoder = new TokyoTyrantTranscoder(5 * 1024 * 1024); } @@ -49,18 +49,20 @@ public boolean equals(Object obj) { } } - - public void testEncodeDecodeLargeValue(){ - List list=new ArrayList(1000000); - for(long i=0;i<1000000;i++){ + + public void testEncodeDecodeLargeValue() { + List list = new ArrayList(1000000); + for (long i = 0; i < 1000000; i++) { list.add(i); } CachedData cachedData = tokyoTyrantTranscoder.encode(list); - List decodeList = (List) tokyoTyrantTranscoder.decode(cachedData); + List decodeList = (List) tokyoTyrantTranscoder + .decode(cachedData); assertNotSame(list, decodeList); assertEquals(list, decodeList); - - List decodeList2 = (List) tokyoTyrantTranscoder.decode(cachedData); + + List decodeList2 = (List) tokyoTyrantTranscoder + .decode(cachedData); assertNotSame(list, decodeList2); assertNotSame(decodeList2, decodeList); assertEquals(list, decodeList2); @@ -74,8 +76,9 @@ public void testDecodeManayTimes() { Person decodePerson = (Person) tokyoTyrantTranscoder.decode(cachedData); assertNotSame(p, decodePerson); assertEquals(p, decodePerson); - - Person decodePerson2 = (Person) tokyoTyrantTranscoder.decode(cachedData); + + Person decodePerson2 = (Person) tokyoTyrantTranscoder + .decode(cachedData); assertNotSame(p, decodePerson2); assertNotSame(decodePerson, decodePerson2); assertEquals(p, decodePerson2); @@ -91,8 +94,8 @@ public void testEncodeDecode() { long currentTimeMillis = System.currentTimeMillis(); cachedData = tokyoTyrantTranscoder.encode(currentTimeMillis); assertEquals(12, cachedData.getData().length); - assertEquals(currentTimeMillis, tokyoTyrantTranscoder - .decode(cachedData)); + assertEquals(currentTimeMillis, + tokyoTyrantTranscoder.decode(cachedData)); cachedData = tokyoTyrantTranscoder.encode("hello"); assertEquals(9, cachedData.getData().length); diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/TranscoderUtilsTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/TranscoderUtilsTest.java index 3a0eb70d7..5211ac047 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/TranscoderUtilsTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/TranscoderUtilsTest.java @@ -11,46 +11,46 @@ public class TranscoderUtilsTest extends TestCase { private TranscoderUtils tu; - byte[] oversizeBytes=new byte[16]; + byte[] oversizeBytes = new byte[16]; @Override protected void setUp() throws Exception { super.setUp(); - tu=new TranscoderUtils(true); + tu = new TranscoderUtils(true); } public void testBooleanOverflow() { try { - boolean b=tu.decodeBoolean(oversizeBytes); + boolean b = tu.decodeBoolean(oversizeBytes); fail("Got " + b + " expected assertion."); - } catch(AssertionError e) { + } catch (AssertionError e) { // pass } } public void testByteOverflow() { try { - byte b=tu.decodeByte(oversizeBytes); + byte b = tu.decodeByte(oversizeBytes); fail("Got " + b + " expected assertion."); - } catch(AssertionError e) { + } catch (AssertionError e) { // pass } } public void testIntOverflow() { try { - int b=tu.decodeInt(oversizeBytes); + int b = tu.decodeInt(oversizeBytes); fail("Got " + b + " expected assertion."); - } catch(AssertionError e) { + } catch (AssertionError e) { // pass } } public void testLongOverflow() { try { - long b=tu.decodeLong(oversizeBytes); + long b = tu.decodeLong(oversizeBytes); fail("Got " + b + " expected assertion."); - } catch(AssertionError e) { + } catch (AssertionError e) { // pass } } @@ -61,6 +61,6 @@ public void testPackedLong() { public void testUnpackedLong() { assertEquals("[0, 0, 0, 0, 0, 0, 0, 1]", - Arrays.toString(new TranscoderUtils(false).encodeLong(1))); + Arrays.toString(new TranscoderUtils(false).encodeLong(1))); } } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/WhalinTranscoderTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/WhalinTranscoderTest.java index ffe968400..4b1aaef21 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/WhalinTranscoderTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/WhalinTranscoderTest.java @@ -9,7 +9,6 @@ import net.rubyeye.xmemcached.transcoders.TranscoderUtils; import net.rubyeye.xmemcached.transcoders.WhalinTranscoder; - /** * Test the serializing transcoder. */ @@ -21,25 +20,25 @@ public class WhalinTranscoderTest extends BaseTranscoderCase { @Override protected void setUp() throws Exception { super.setUp(); - tc=new WhalinTranscoder(); + tc = new WhalinTranscoder(); setTranscoder(tc); - tu=new TranscoderUtils(false); + tu = new TranscoderUtils(false); } public void testNonserializable() throws Exception { try { tc.encode(new Object()); fail("Processed a non-serializable object."); - } catch(IllegalArgumentException e) { + } catch (IllegalArgumentException e) { // pass } } public void testCompressedStringNotSmaller() throws Exception { - String s1="This is a test simple string that will not be compressed."; + String s1 = "This is a test simple string that will not be compressed."; // Reduce the compression threshold so it'll attempt to compress it. tc.setCompressionThreshold(8); - CachedData cd=tc.encode(s1); + CachedData cd = tc.encode(s1); // This should *not* be compressed because it is too small assertEquals(WhalinTranscoder.SPECIAL_STRING, cd.getFlag()); assertTrue(Arrays.equals(s1.getBytes(), cd.getData())); @@ -48,61 +47,57 @@ public void testCompressedStringNotSmaller() throws Exception { public void testCompressedString() throws Exception { // This one will actually compress - String s1="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + String s1 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; tc.setCompressionThreshold(8); - CachedData cd=tc.encode(s1); + CachedData cd = tc.encode(s1); assertEquals( - WhalinTranscoder.COMPRESSED | WhalinTranscoder.SPECIAL_STRING, - cd.getFlag()); + WhalinTranscoder.COMPRESSED | WhalinTranscoder.SPECIAL_STRING, + cd.getFlag()); assertFalse(Arrays.equals(s1.getBytes(), cd.getData())); assertEquals(s1, tc.decode(cd)); } public void testObject() throws Exception { - Calendar c=Calendar.getInstance(); - CachedData cd=tc.encode(c); + Calendar c = Calendar.getInstance(); + CachedData cd = tc.encode(c); assertEquals(WhalinTranscoder.SERIALIZED, cd.getFlag()); assertEquals(c, tc.decode(cd)); } public void testCompressedObject() throws Exception { tc.setCompressionThreshold(8); - Calendar c=Calendar.getInstance(); - CachedData cd=tc.encode(c); - assertEquals(WhalinTranscoder.SERIALIZED - |WhalinTranscoder.COMPRESSED, cd.getFlag()); + Calendar c = Calendar.getInstance(); + CachedData cd = tc.encode(c); + assertEquals(WhalinTranscoder.SERIALIZED | WhalinTranscoder.COMPRESSED, + cd.getFlag()); assertEquals(c, tc.decode(cd)); } public void testUnencodeable() throws Exception { try { - CachedData cd=tc.encode(new Object()); + CachedData cd = tc.encode(new Object()); fail("Should fail to serialize, got" + cd); - } catch(IllegalArgumentException e) { + } catch (IllegalArgumentException e) { // pass } } public void testUndecodeable() throws Exception { - CachedData cd=new CachedData( - Integer.MAX_VALUE & - ~(WhalinTranscoder.COMPRESSED | WhalinTranscoder.SERIALIZED), - tu.encodeInt(Integer.MAX_VALUE), - tc.getMaxSize(),-1); + CachedData cd = new CachedData(Integer.MAX_VALUE + & ~(WhalinTranscoder.COMPRESSED | WhalinTranscoder.SERIALIZED), + tu.encodeInt(Integer.MAX_VALUE), tc.getMaxSize(), -1); assertNull(tc.decode(cd)); } public void testUndecodeableSerialized() throws Exception { - CachedData cd=new CachedData(WhalinTranscoder.SERIALIZED, - tu.encodeInt(Integer.MAX_VALUE), - tc.getMaxSize(),-1); + CachedData cd = new CachedData(WhalinTranscoder.SERIALIZED, + tu.encodeInt(Integer.MAX_VALUE), tc.getMaxSize(), -1); assertNull(tc.decode(cd)); } public void testUndecodeableCompressed() throws Exception { - CachedData cd=new CachedData(WhalinTranscoder.COMPRESSED, - tu.encodeInt(Integer.MAX_VALUE), - tc.getMaxSize(),-1); + CachedData cd = new CachedData(WhalinTranscoder.COMPRESSED, + tu.encodeInt(Integer.MAX_VALUE), tc.getMaxSize(), -1); assertNull(tc.decode(cd)); } diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/WhalinV1TranscoderTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/WhalinV1TranscoderTest.java index 88c6cbfbf..8d5d11a25 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/WhalinV1TranscoderTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/transcoder/WhalinV1TranscoderTest.java @@ -3,7 +3,6 @@ import net.rubyeye.xmemcached.transcoders.CachedData; import net.rubyeye.xmemcached.transcoders.WhalinV1Transcoder; - public class WhalinV1TranscoderTest extends BaseTranscoderCase { @Override @@ -14,7 +13,7 @@ protected void setUp() throws Exception { @Override public void testByteArray() throws Exception { - byte[] a = { 'a', 'b', 'c' }; + byte[] a = {'a', 'b', 'c'}; try { CachedData cd = getTranscoder().encode(a); fail("Expected IllegalArgumentException, got " + cd); diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/utils/AddrUtilTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/utils/AddrUtilTest.java index 0b931627a..69ecad06a 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/utils/AddrUtilTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/utils/AddrUtilTest.java @@ -22,7 +22,8 @@ public void testGetAddresses() { AddrUtil.getAddresses(" "); fail(); } catch (IllegalArgumentException e) { - assertEquals("No hosts in list: ``" + " " + "''", e.getMessage()); + assertEquals("No hosts in list: ``" + " " + "''", + e.getMessage()); } List addresses = AddrUtil @@ -83,7 +84,8 @@ public void testGetAddressMap_IllegalArgument() { @Test public void testGetAddressMap_OnlyMainAddr() { Map addressMap = AddrUtil - .getAddressMap("localhost:12000 localhost:12001 localhost:12002 "); + .getAddressMap( + "localhost:12000 localhost:12001 localhost:12002 "); assertEquals(3, addressMap.size()); assertNull(addressMap.get(new InetSocketAddress("localhost", 12002))); assertNull(addressMap.get(new InetSocketAddress("localhost", 12000))); @@ -93,10 +95,11 @@ public void testGetAddressMap_OnlyMainAddr() { @Test public void testGetAddressMap() { Map addressMap = AddrUtil - .getAddressMap("localhost:12000,localhost:12001 localhost:12002 localhost:12001,localhost:12003"); + .getAddressMap( + "localhost:12000,localhost:12001 localhost:12002 localhost:12001,localhost:12003"); assertEquals(3, addressMap.size()); - assertEquals(new InetSocketAddress("localhost", 12001), addressMap - .get(new InetSocketAddress("localhost", 12000))); + assertEquals(new InetSocketAddress("localhost", 12001), + addressMap.get(new InetSocketAddress("localhost", 12000))); assertNull(addressMap.get(new InetSocketAddress("localhost", 12002))); assertEquals(addressMap.get(new InetSocketAddress("localhost", 12001)), new InetSocketAddress("localhost", 12003)); diff --git a/src/test/java/net/rubyeye/xmemcached/test/unittest/utils/OpaqueGeneraterUnitTest.java b/src/test/java/net/rubyeye/xmemcached/test/unittest/utils/OpaqueGeneraterUnitTest.java index af22d5780..38e31daa3 100644 --- a/src/test/java/net/rubyeye/xmemcached/test/unittest/utils/OpaqueGeneraterUnitTest.java +++ b/src/test/java/net/rubyeye/xmemcached/test/unittest/utils/OpaqueGeneraterUnitTest.java @@ -7,7 +7,7 @@ import static junit.framework.Assert.*; import net.rubyeye.xmemcached.utils.OpaqueGenerater; -public class OpaqueGeneraterUnitTest extends TestCase{ +public class OpaqueGeneraterUnitTest extends TestCase { public void testGetNextValue() throws Exception { OpaqueGenerater.getInstance().setValue(Integer.MAX_VALUE - 10000); @@ -19,7 +19,8 @@ public void run() { try { barrier.await(); for (int i = 0; i < 10000; i++) { - if (OpaqueGenerater.getInstance().getNextValue() < 0) + if (OpaqueGenerater.getInstance() + .getNextValue() < 0) throw new RuntimeException("Test failed."); } barrier.await(); From 555d72f542420e6abe27e84ecb6617d317ba8078 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Fri, 24 Nov 2017 10:33:06 +0800 Subject: [PATCH 123/207] (fix) An implicit bug in KetamaMemcachedSessionLocator --- .../google/code/yanf4j/util/SystemUtils.java | 323 +++++++++--------- .../impl/KetamaMemcachedSessionLocator.java | 105 ++++-- 2 files changed, 233 insertions(+), 195 deletions(-) diff --git a/src/main/java/com/google/code/yanf4j/util/SystemUtils.java b/src/main/java/com/google/code/yanf4j/util/SystemUtils.java index c2c6ccc24..cca0ea643 100644 --- a/src/main/java/com/google/code/yanf4j/util/SystemUtils.java +++ b/src/main/java/com/google/code/yanf4j/util/SystemUtils.java @@ -1,159 +1,164 @@ -/** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 - */ -/** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 com.google.code.yanf4j.util; - -import java.io.IOException; -import java.lang.reflect.Method; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.nio.channels.Selector; -import java.nio.channels.spi.SelectorProvider; -import java.util.Queue; - -/** - * System utils - * - * @author dennis - * - */ -public final class SystemUtils { - - private SystemUtils() { - - } - - public static final String OS_NAME = System.getProperty("os.name"); - - private static boolean isLinuxPlatform = false; - - static { - if (OS_NAME != null && OS_NAME.toLowerCase().indexOf("linux") >= 0) { - isLinuxPlatform = true; - } - } - public static final String JAVA_VERSION = System - .getProperty("java.version"); - private static boolean isAfterJava6u4Version = false; - static { - if (JAVA_VERSION != null) { - // java4 or java5 - if (JAVA_VERSION.indexOf("1.4.") >= 0 - || JAVA_VERSION.indexOf("1.5.") >= 0) { - isAfterJava6u4Version = false; - } else if (JAVA_VERSION.indexOf("1.6.") >= 0) { - int index = JAVA_VERSION.indexOf("_"); - if (index > 0) { - String subVersionStr = JAVA_VERSION.substring(index + 1); - if (subVersionStr != null && subVersionStr.length() > 0) { - try { - int subVersion = Integer.parseInt(subVersionStr); - if (subVersion >= 4) { - isAfterJava6u4Version = true; - } - } catch (NumberFormatException e) { - - } - } - } - // after java6 - } else { - isAfterJava6u4Version = true; - } - } - } - - public static final boolean isLinuxPlatform() { - return isLinuxPlatform; - } - - public static final boolean isAfterJava6u4Version() { - return isAfterJava6u4Version; - } - - public static void main(String[] args) { - System.out.println(isAfterJava6u4Version()); - } - - public static final int getSystemThreadCount() { - int cpus = getCpuProcessorCount(); - if (cpus <= 8) { - return cpus; - } else { - return 8 + (cpus - 8) * 5 / 8; - } - } - - public static final int getCpuProcessorCount() { - return Runtime.getRuntime().availableProcessors(); - } - - public static final Selector openSelector() throws IOException { - Selector result = null; - // check if it is linux os - if (SystemUtils.isLinuxPlatform()) { - try { - Class providerClazz = Class - .forName("sun.nio.ch.EPollSelectorProvider"); - if (providerClazz != null) { - try { - Method method = providerClazz.getMethod("provider"); - if (method != null) { - SelectorProvider selectorProvider = (SelectorProvider) method - .invoke(null); - if (selectorProvider != null) { - result = selectorProvider.openSelector(); - } - } - } catch (Exception e) { - // ignore - } - } - } catch (Exception e) { - // ignore - } - } - if (result == null) { - result = Selector.open(); - } - return result; - - } - - public static final String getRawAddress( - InetSocketAddress inetSocketAddress) { - InetAddress address = inetSocketAddress.getAddress(); - return address != null - ? address.getHostAddress() - : inetSocketAddress.getHostName(); - } - - public static final Queue createTransferQueue() { - try { - return (Queue) Class - .forName("java.util.concurrent.LinkedTransferQueue") - .newInstance(); - } catch (Exception e) { - return new LinkedTransferQueue(); - } - } -} +/** + *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] + *Licensed 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 + */ +/** + *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] + *Licensed 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 com.google.code.yanf4j.util; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.nio.channels.Selector; +import java.nio.channels.spi.SelectorProvider; +import java.util.Queue; +import java.util.Random; + +/** + * System utils + * + * @author dennis + * + */ +public final class SystemUtils { + + private SystemUtils() { + + } + + public static final String OS_NAME = System.getProperty("os.name"); + + private static boolean isLinuxPlatform = false; + + static { + if (OS_NAME != null && OS_NAME.toLowerCase().indexOf("linux") >= 0) { + isLinuxPlatform = true; + } + } + public static final String JAVA_VERSION = System + .getProperty("java.version"); + private static boolean isAfterJava6u4Version = false; + static { + if (JAVA_VERSION != null) { + // java4 or java5 + if (JAVA_VERSION.indexOf("1.4.") >= 0 + || JAVA_VERSION.indexOf("1.5.") >= 0) { + isAfterJava6u4Version = false; + } else if (JAVA_VERSION.indexOf("1.6.") >= 0) { + int index = JAVA_VERSION.indexOf("_"); + if (index > 0) { + String subVersionStr = JAVA_VERSION.substring(index + 1); + if (subVersionStr != null && subVersionStr.length() > 0) { + try { + int subVersion = Integer.parseInt(subVersionStr); + if (subVersion >= 4) { + isAfterJava6u4Version = true; + } + } catch (NumberFormatException e) { + + } + } + } + // after java6 + } else { + isAfterJava6u4Version = true; + } + } + } + + public static final boolean isLinuxPlatform() { + return isLinuxPlatform; + } + + public static final boolean isAfterJava6u4Version() { + return isAfterJava6u4Version; + } + + public static void main(String[] args) { + System.out.println(isAfterJava6u4Version()); + } + + public static final int getSystemThreadCount() { + int cpus = getCpuProcessorCount(); + if (cpus <= 8) { + return cpus; + } else { + return 8 + (cpus - 8) * 5 / 8; + } + } + + public static final int getCpuProcessorCount() { + return Runtime.getRuntime().availableProcessors(); + } + + public static final Selector openSelector() throws IOException { + Selector result = null; + // check if it is linux os + if (SystemUtils.isLinuxPlatform()) { + try { + Class providerClazz = Class + .forName("sun.nio.ch.EPollSelectorProvider"); + if (providerClazz != null) { + try { + Method method = providerClazz.getMethod("provider"); + if (method != null) { + SelectorProvider selectorProvider = (SelectorProvider) method + .invoke(null); + if (selectorProvider != null) { + result = selectorProvider.openSelector(); + } + } + } catch (Exception e) { + // ignore + } + } + } catch (Exception e) { + // ignore + } + } + if (result == null) { + result = Selector.open(); + } + return result; + + } + + public static final String getRawAddress( + InetSocketAddress inetSocketAddress) { + InetAddress address = inetSocketAddress.getAddress(); + return address != null + ? address.getHostAddress() + : inetSocketAddress.getHostName(); + } + + public static final Queue createTransferQueue() { + try { + return (Queue) Class + .forName("java.util.concurrent.LinkedTransferQueue") + .newInstance(); + } catch (Exception e) { + return new LinkedTransferQueue(); + } + } + + public static Random createRandom() { + return new Random(); + } +} diff --git a/src/main/java/net/rubyeye/xmemcached/impl/KetamaMemcachedSessionLocator.java b/src/main/java/net/rubyeye/xmemcached/impl/KetamaMemcachedSessionLocator.java index 47509ffbf..fba49e547 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/KetamaMemcachedSessionLocator.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/KetamaMemcachedSessionLocator.java @@ -14,15 +14,17 @@ import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; import java.util.List; -import java.util.Random; import java.util.SortedMap; import java.util.TreeMap; +import com.google.code.yanf4j.core.Session; + import net.rubyeye.xmemcached.HashAlgorithm; import net.rubyeye.xmemcached.networking.MemcachedSession; - -import com.google.code.yanf4j.core.Session; +import net.rubyeye.xmemcached.utils.InetSocketAddressWrapper; /** * ConnectionFactory instance that sets up a ketama compatible connection. @@ -42,9 +44,9 @@ /** * Consistent Hash Algorithm implementation,based on TreeMap.tailMap(hash) * method. - * + * * @author dennis - * + * */ public class KetamaMemcachedSessionLocator extends @@ -54,7 +56,6 @@ public class KetamaMemcachedSessionLocator private transient volatile TreeMap> ketamaSessions = new TreeMap>(); private final HashAlgorithm hashAlg; private int maxTries; - private final Random random = new Random(); /** * compatible with nginx-upstream-consistent,patched by wolfg1969 @@ -63,18 +64,33 @@ public class KetamaMemcachedSessionLocator private final boolean cwNginxUpstreamConsistent; private final boolean gwhalinMemcachedJavaClientCompatibiltyConsistent; + /** + * Create a KetamaMemcachedSessionLocator with default config. + */ public KetamaMemcachedSessionLocator() { this.hashAlg = HashAlgorithm.KETAMA_HASH; this.cwNginxUpstreamConsistent = false; this.gwhalinMemcachedJavaClientCompatibiltyConsistent = false; } + /** + * Create a KetamaMemcachedSessionLocator + * + * @param cwNginxUpstreamConsistent + * true if compatible with nginx up stream memcached consistent + * algorithm. + */ public KetamaMemcachedSessionLocator(boolean cwNginxUpstreamConsistent) { this.hashAlg = HashAlgorithm.KETAMA_HASH; this.cwNginxUpstreamConsistent = cwNginxUpstreamConsistent; this.gwhalinMemcachedJavaClientCompatibiltyConsistent = false; } + /** + * Create a KetamaMemcachedSessionLocator with a special hash algorithm. + * + * @param alg + */ public KetamaMemcachedSessionLocator(HashAlgorithm alg) { this.hashAlg = alg; this.cwNginxUpstreamConsistent = false; @@ -109,35 +125,7 @@ private final void buildMap(Collection list, HashAlgorithm alg) { TreeMap> sessionMap = new TreeMap>(); for (Session session : list) { - String sockStr = null; - if (this.cwNginxUpstreamConsistent) { - InetSocketAddress serverAddress = session - .getRemoteSocketAddress(); - sockStr = serverAddress.getAddress().getHostAddress(); - if (serverAddress.getPort() != DEFAULT_PORT) { - sockStr = sockStr + ":" + serverAddress.getPort(); - } - } else { - if (session instanceof MemcachedSession) { - if (!gwhalinMemcachedJavaClientCompatibiltyConsistent) { - // Always use the first time resolved address. - sockStr = ((MemcachedSession) session) - .getInetSocketAddressWrapper() - .getRemoteAddressStr(); - } else { - sockStr = ((MemcachedSession) session) - .getInetSocketAddressWrapper() - .getInetSocketAddress().getHostName() - + ":" - + ((MemcachedSession) session) - .getInetSocketAddressWrapper() - .getInetSocketAddress().getPort(); - } - } - if (sockStr == null) { - sockStr = String.valueOf(session.getRemoteSocketAddress()); - } - } + String sockStr = this.getSockStr(session); /** * Duplicate 160 X weight references */ @@ -164,10 +152,55 @@ private final void buildMap(Collection list, HashAlgorithm alg) { } } } + // sort session list. + for (List sessions : sessionMap.values()) { + Collections.sort(sessions, new Comparator() { + + public int compare(Session o1, Session o2) { + String sockStr1 = KetamaMemcachedSessionLocator.this + .getSockStr(o1); + String sockStr2 = KetamaMemcachedSessionLocator.this + .getSockStr(o2); + return sockStr1.compareTo(sockStr2); + } + + }); + } this.ketamaSessions = sessionMap; this.maxTries = list.size(); } + private String getSockStr(Session session) { + String sockStr = null; + if (this.cwNginxUpstreamConsistent) { + InetSocketAddress serverAddress = session.getRemoteSocketAddress(); + sockStr = serverAddress.getAddress().getHostAddress(); + if (serverAddress.getPort() != DEFAULT_PORT) { + sockStr = sockStr + ":" + serverAddress.getPort(); + } + } else { + if (session instanceof MemcachedSession) { + MemcachedSession memcachedSession = (MemcachedSession) session; + InetSocketAddressWrapper inetSocketAddressWrapper = memcachedSession + .getInetSocketAddressWrapper(); + if (this.gwhalinMemcachedJavaClientCompatibiltyConsistent) { + sockStr = inetSocketAddressWrapper.getInetSocketAddress() + .getHostName() + ":" + + inetSocketAddressWrapper.getInetSocketAddress() + .getPort(); + + } else { + // Always use the first time resolved address. + sockStr = inetSocketAddressWrapper.getRemoteAddressStr(); + } + } + if (sockStr == null) { + sockStr = String.valueOf(session.getRemoteSocketAddress()); + } + } + return sockStr; + } + private List getSessionList( TreeMap> sessionMap, long k) { List sessionList = sessionMap.get(k); @@ -221,7 +254,7 @@ public final Session getSessionByHash(final long hash) { return null; } int size = sessionList.size(); - return sessionList.get(this.random.nextInt(size)); + return sessionList.get((int) (resultHash % size)); } public final long nextHash(long hashVal, String key, int tries) { From 0d9f18e124820409f548dbad58febf4a86670864 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Fri, 24 Nov 2017 10:57:31 +0800 Subject: [PATCH 124/207] (feat) Adds CLEAR_THRESHOLD to CachedString --- .../xmemcached/utils/CachedString.java | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/main/java/net/rubyeye/xmemcached/utils/CachedString.java b/src/main/java/net/rubyeye/xmemcached/utils/CachedString.java index 423fd5086..d6f7dd846 100644 --- a/src/main/java/net/rubyeye/xmemcached/utils/CachedString.java +++ b/src/main/java/net/rubyeye/xmemcached/utils/CachedString.java @@ -3,19 +3,20 @@ import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; -import java.util.Arrays; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import javax.management.RuntimeErrorException; - public class CachedString { private static ConcurrentHashMap> table = new ConcurrentHashMap(); static final ReferenceQueue rq = new ReferenceQueue(); + public static final int CLEAR_THRESHOLD = Integer.parseInt( + System.getProperty("xmemcached.string.bytes.cached.clear_threshold", + "1000")); public static byte[] getBytes(String s) { - if (s == null || s.length() == 0) + if (s == null || s.length() == 0) { return null; + } byte[] bs = null; Reference existingRef = table.get(s); if (existingRef == null) { @@ -38,13 +39,17 @@ public static byte[] getBytes(String s) { static public void clearCache(ReferenceQueue rq, ConcurrentHashMap> cache) { - // cleanup any dead entries - if (rq.poll() != null) { - while (rq.poll() != null); - for (Map.Entry> e : cache.entrySet()) { - Reference val = e.getValue(); - if (val != null && val.get() == null) { - cache.remove(e.getKey(), val); + if (cache.size() > CLEAR_THRESHOLD) { + // cleanup any dead entries + if (rq.poll() != null) { + while (rq.poll() != null) { + ; + } + for (Map.Entry> e : cache.entrySet()) { + Reference val = e.getValue(); + if (val != null && val.get() == null) { + cache.remove(e.getKey(), val); + } } } } From ad0744f25e0c1585536fe4b491399b61e9ff7819 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Fri, 24 Nov 2017 11:29:54 +0800 Subject: [PATCH 125/207] (feat) Adds FastStringEncoder --- .../xmemcached/utils/CachedString.java | 2 +- .../xmemcached/utils/FastStringEncoder.java | 116 ++++++++++++++++++ 2 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 src/main/java/net/rubyeye/xmemcached/utils/FastStringEncoder.java diff --git a/src/main/java/net/rubyeye/xmemcached/utils/CachedString.java b/src/main/java/net/rubyeye/xmemcached/utils/CachedString.java index d6f7dd846..72e933fb5 100644 --- a/src/main/java/net/rubyeye/xmemcached/utils/CachedString.java +++ b/src/main/java/net/rubyeye/xmemcached/utils/CachedString.java @@ -61,7 +61,7 @@ private static long testString(int keyLen) { for (int i = 0; i < 1000; i++) { // byte[] bs = k.getBytes(ByteUtils.DEFAULT_CHARSET); // String nk = new String(bs, ByteUtils.DEFAULT_CHARSET); - byte[] bs = getBytes(k); + byte[] bs = FastStringEncoder.encodeUTF8(k); String nk = ByteUtils.getString(bs); if (!k.equals(nk)) { throw new RuntimeException(); diff --git a/src/main/java/net/rubyeye/xmemcached/utils/FastStringEncoder.java b/src/main/java/net/rubyeye/xmemcached/utils/FastStringEncoder.java new file mode 100644 index 000000000..2eb57f64a --- /dev/null +++ b/src/main/java/net/rubyeye/xmemcached/utils/FastStringEncoder.java @@ -0,0 +1,116 @@ +package net.rubyeye.xmemcached.utils; + +import java.util.Arrays; + +/** + * Fast string utf encoder. + * + * @author dennis + * + */ +public class FastStringEncoder { + + public static void main(String[] args) throws Exception { + System.out.println(encodeUTF8("test").length); + System.out.println(new String(encodeUTF8("test"), "utf-8")); + System.out.println(encodeUTF8("测试下中文").length); + System.out.println(new String(encodeUTF8("测试下中文"), "utf-8")); + } + + private static ThreadLocal bufLocal = new ThreadLocal(); + + private static byte[] getBuf(int length) { + byte[] buf = bufLocal.get(); + if (buf != null) { + bufLocal.set(null); + } else { + buf = new byte[length < 128 ? 128 : length]; + } + return buf; + } + + private static void close(byte[] buf) { + if (buf.length <= 1024 * 64) { + bufLocal.set(buf); + } + } + + private static byte[] expandCapacity(byte[] buf, int minNewCapacity) { + int newCapacity = buf.length + (buf.length >> 1) + 1; + if (newCapacity < minNewCapacity) { + newCapacity = minNewCapacity; + } + return Arrays.copyOf(buf, newCapacity); + } + + public static byte[] encodeUTF8(String s) { + int len = s.length(); + byte[] bytes = getBuf(len); + + int offset = 0; + int sl = offset + len; + int dp = 0; + int dlASCII = dp + Math.min(len, bytes.length); + + // ASCII only optimized loop + while (dp < dlASCII && s.charAt(offset) < '\u0080') { + bytes[dp++] = (byte) s.charAt(offset++); + } + + while (offset < sl) { + if (dp >= bytes.length - 1) { + bytes = expandCapacity(bytes, len); + } + char c = s.charAt(offset++); + if (c < 0x80) { + // Have at most seven bits + bytes[dp++] = (byte) c; + } else if (c < 0x800) { + // 2 bytes, 11 bits + bytes[dp++] = (byte) (0xc0 | c >> 6); + bytes[dp++] = (byte) (0x80 | c & 0x3f); + } else if (c >= '\uD800' && c < '\uDFFF' + 1) { // Character.isSurrogate(c) + // but 1.7 + final int uc; + int ip = offset - 1; + if (Character.isHighSurrogate(c)) { + if (sl - ip < 2) { + uc = -1; + } else { + char d = s.charAt(ip + 1); + if (Character.isLowSurrogate(d)) { + uc = Character.toCodePoint(c, d); + } else { + throw new IllegalStateException("encodeUTF8 error"); + } + } + } else { + if (Character.isLowSurrogate(c)) { + throw new IllegalStateException("encodeUTF8 error"); + } else { + uc = c; + } + } + + if (uc < 0) { + bytes[dp++] = (byte) '?'; + } else { + bytes[dp++] = (byte) (0xf0 | uc >> 18); + bytes[dp++] = (byte) (0x80 | uc >> 12 & 0x3f); + bytes[dp++] = (byte) (0x80 | uc >> 6 & 0x3f); + bytes[dp++] = (byte) (0x80 | uc & 0x3f); + offset++; // 2 chars + } + } else { + // 3 bytes, 16 bits + bytes[dp++] = (byte) (0xe0 | c >> 12); + bytes[dp++] = (byte) (0x80 | c >> 6 & 0x3f); + bytes[dp++] = (byte) (0x80 | c & 0x3f); + } + } + byte[] resultBytes = new byte[dp]; + System.arraycopy(bytes, 0, resultBytes, 0, dp); + close(bytes); + return resultBytes; + } +} From 6590c4e4d887781848fcf5e99928040d59a5a05a Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Mon, 27 Nov 2017 18:06:38 +0800 Subject: [PATCH 126/207] (feat) fast ByteUtils.getBytes --- .../rubyeye/xmemcached/utils/ByteUtils.java | 54 +++++++++---------- .../xmemcached/utils/FastStringEncoder.java | 14 ++--- .../unittest/utils/FastStringEncoderTest.java | 51 ++++++++++++++++++ 3 files changed, 81 insertions(+), 38 deletions(-) create mode 100644 src/test/java/com/google/code/yanf4j/test/unittest/utils/FastStringEncoderTest.java diff --git a/src/main/java/net/rubyeye/xmemcached/utils/ByteUtils.java b/src/main/java/net/rubyeye/xmemcached/utils/ByteUtils.java index 14fefe2b7..1138ff901 100644 --- a/src/main/java/net/rubyeye/xmemcached/utils/ByteUtils.java +++ b/src/main/java/net/rubyeye/xmemcached/utils/ByteUtils.java @@ -15,19 +15,19 @@ import java.nio.ByteBuffer; import java.nio.charset.Charset; -import net.rubyeye.xmemcached.codec.MemcachedDecoder; -import net.rubyeye.xmemcached.monitor.Constants; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.code.yanf4j.buffer.IoBuffer; +import net.rubyeye.xmemcached.codec.MemcachedDecoder; +import net.rubyeye.xmemcached.monitor.Constants; + /** * Utilities for byte process - * + * * @author dennis - * + * */ public final class ByteUtils { public static final Logger log = LoggerFactory.getLogger(ByteUtils.class); @@ -76,14 +76,7 @@ public static final byte[] getBytes(String k) { if (k == null || k.length() == 0) { throw new IllegalArgumentException("Key must not be blank"); } - if (ENABLE_CACHED_STRING_BYTES) { - return CachedString.getBytes(k); - } - try { - return k.getBytes(DEFAULT_CHARSET_NAME); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } + return FastStringEncoder.encodeUTF8(k); } public static final void setArguments(IoBuffer bb, Object... args) { @@ -260,7 +253,7 @@ public static final boolean stepBuffer(ByteBuffer buffer, int remaining) { /** * Read next line from ByteBuffer - * + * * @param buffer * @return */ @@ -295,8 +288,8 @@ public static String getString(byte[] bytes) { public static void byte2hex(byte b, StringBuffer buf) { char[] hexChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; - int high = ((b & 0xf0) >> 4); - int low = (b & 0x0f); + int high = (b & 0xf0) >> 4; + int low = b & 0x0f; buf.append(hexChars[high]); buf.append(hexChars[low]); } @@ -345,12 +338,13 @@ public static void getBytes(long i, int index, byte[] buf) { // Fall thru to fast mode for smaller numbers // assert(i2 <= 65536, i2); for (;;) { - q2 = (i2 * 52429) >>> (16 + 3); + q2 = i2 * 52429 >>> 16 + 3; r = i2 - ((q2 << 3) + (q2 << 1)); // r = i2-(q2*10) ... buf[--pos] = digits[r]; i2 = q2; - if (i2 == 0) + if (i2 == 0) { break; + } } if (sign != 0) { buf[--pos] = sign; @@ -362,7 +356,7 @@ public static void getBytes(long i, int index, byte[] buf) { * buf. The characters are placed into the buffer backwards starting with * the least significant digit at the specified index (exclusive), and * working backwards from there. - * + * * Will fail if i == Integer.MIN_VALUE */ static void getBytes(int i, int index, byte[] buf) { @@ -388,12 +382,13 @@ static void getBytes(int i, int index, byte[] buf) { // Fall thru to fast mode for smaller numbers // assert(i <= 65536, i); for (;;) { - q = (i * 52429) >>> (16 + 3); + q = i * 52429 >>> 16 + 3; r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ... buf[--pos] = digits[r]; i = q; - if (i == 0) + if (i == 0) { break; + } } if (sign != 0) { buf[--pos] = sign; @@ -433,17 +428,20 @@ static void getBytes(int i, int index, byte[] buf) { // Requires positive x public static final int stringSize(int x) { - for (int i = 0;; i++) - if (x <= sizeTable[i]) + for (int i = 0;; i++) { + if (x <= sizeTable[i]) { return i + 1; + } + } } // Requires positive x public static final int stringSize(long x) { long p = 10; for (int i = 1; i < 19; i++) { - if (x < p) + if (x < p) { return i; + } p = 10 * p; } return 19; @@ -452,7 +450,7 @@ public static final int stringSize(long x) { final static int[] byte_len_array = new int[256]; static { for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; ++i) { - int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i); + int size = i < 0 ? stringSize(-i) + 1 : stringSize(i); byte_len_array[i & 0xFF] = size; } } @@ -470,7 +468,7 @@ public static byte int1(int x) { } public static byte int0(int x) { - return (byte) (x); + return (byte) x; } public static byte short1(short x) { @@ -478,7 +476,7 @@ public static byte short1(short x) { } public static byte short0(short x) { - return (byte) (x); + return (byte) x; } public static byte long7(long x) { @@ -510,6 +508,6 @@ public static byte long1(long x) { } public static byte long0(long x) { - return (byte) (x); + return (byte) x; } } diff --git a/src/main/java/net/rubyeye/xmemcached/utils/FastStringEncoder.java b/src/main/java/net/rubyeye/xmemcached/utils/FastStringEncoder.java index 2eb57f64a..b4fa9f5e4 100644 --- a/src/main/java/net/rubyeye/xmemcached/utils/FastStringEncoder.java +++ b/src/main/java/net/rubyeye/xmemcached/utils/FastStringEncoder.java @@ -10,13 +10,7 @@ */ public class FastStringEncoder { - public static void main(String[] args) throws Exception { - System.out.println(encodeUTF8("test").length); - System.out.println(new String(encodeUTF8("test"), "utf-8")); - System.out.println(encodeUTF8("测试下中文").length); - System.out.println(new String(encodeUTF8("测试下中文"), "utf-8")); - } - + private static final int STEP = 128; private static ThreadLocal bufLocal = new ThreadLocal(); private static byte[] getBuf(int length) { @@ -24,7 +18,7 @@ private static byte[] getBuf(int length) { if (buf != null) { bufLocal.set(null); } else { - buf = new byte[length < 128 ? 128 : length]; + buf = new byte[length < STEP ? STEP : length]; } return buf; } @@ -58,8 +52,8 @@ public static byte[] encodeUTF8(String s) { } while (offset < sl) { - if (dp >= bytes.length - 1) { - bytes = expandCapacity(bytes, len); + if (dp >= bytes.length - 4) { + bytes = expandCapacity(bytes, bytes.length + STEP * 2); } char c = s.charAt(offset++); if (c < 0x80) { diff --git a/src/test/java/com/google/code/yanf4j/test/unittest/utils/FastStringEncoderTest.java b/src/test/java/com/google/code/yanf4j/test/unittest/utils/FastStringEncoderTest.java new file mode 100644 index 000000000..e92801d8b --- /dev/null +++ b/src/test/java/com/google/code/yanf4j/test/unittest/utils/FastStringEncoderTest.java @@ -0,0 +1,51 @@ +package com.google.code.yanf4j.test.unittest.utils; + +import static org.junit.Assert.assertEquals; + +import java.util.UUID; + +import org.junit.Test; + +import net.rubyeye.xmemcached.utils.ByteUtils; +import net.rubyeye.xmemcached.utils.FastStringEncoder; + +public class FastStringEncoderTest { + + @Test + public void testASCII() { + this.assertEncodeEquals("hello world!@#$%^&*()_+|"); + for (int i = 0; i < 10000; i++) { + String uuid = UUID.randomUUID().toString(); + this.assertEncodeEquals(uuid); + } + } + + private void assertEncodeEquals(String s) { + assertEquals(s, ByteUtils.getString(FastStringEncoder.encodeUTF8(s))); + } + + @Test + public void testCJK() { + this.assertEncodeEquals("中华人民共和国"); + this.assertEncodeEquals("我能吞下玻璃而不傷身體"); + this.assertEncodeEquals("驚いた彼は道を走っていった。"); + this.assertEncodeEquals(" 나는 유리를 먹을 수 있어요. 그래도 아프지 않아요"); + this.assertEncodeEquals("私はガラスを食べられます。それは私を傷つけません"); + this.assertEncodeEquals("ฉันกินกระจกได้ แต่มันไม่ทำให้ฉันเจ็บ"); + } + + @Test + public void testBigString() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 65535; i++) { + sb.append("a"); + } + this.assertEncodeEquals(sb.toString()); + } + + @Test + public void testEmoj() { + this.assertEncodeEquals( + "😀 😃 😄 😁 😆 😅 😂 🤣 ☺️ 😊 😇 🙂 🙃 😉 😌 😍 😘 😗 😙 😚 😋 😜 😝 😛 🤑 🤗 🤓 😎 🤡 🤠 😏 😒 😞 😔 😟 😕 🙁 ☹️ 😣 😖 😫 😩 😤 😠 😡 😶 😐 😑 😯 😦 😧 😮 😲 😵 😳 😱 😨 😰 😢 😥 🤤 😭 😓 😪 😴 🙄 🤔 🤥 😬 🤐 🤢 🤧 😷 🤒 🤕 😈 👿 👹 👺 💩 👻 💀 ☠️ 👽 👾 🤖 🎃 😺 😸 😹 😻 😼 😽 🙀 😿 😾 "); + } +} From 62b7379e22ba9a7eb28cfeefdec4cf641d26c39d Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Thu, 22 Feb 2018 16:52:48 +0800 Subject: [PATCH 127/207] (fix) old sessions were kept when memcached server changed IP address with failure mode, close #68 --- .../xmemcached/impl/MemcachedConnector.java | 45 +++++++++++++++++-- .../utils/InetSocketAddressWrapper.java | 24 ++++++++-- 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java index 63cd2fa27..90e49d42a 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java @@ -241,21 +241,41 @@ public synchronized void addSession(Session session) { InetSocketAddress mainNodeAddress = addrWrapper.getMainNodeAddress(); if (mainNodeAddress != null) { // It is a standby session - this.addStandbySession(session, mainNodeAddress); + this.addStandbySession(session, mainNodeAddress, + addrWrapper.getResolvedMainNodeSocketAddress(), + addrWrapper); } else { // It is a main session - this.addMainSession(session); + this.addMainSession(session, addrWrapper.getResolvedSocketAddress(), + addrWrapper); // Update main sessions this.updateSessions(); } } - private void addMainSession(Session session) { + private void addMainSession(Session session, + InetSocketAddress lastReolvedAddr, + InetSocketAddressWrapper addrWrapper) { InetSocketAddress remoteSocketAddress = session .getRemoteSocketAddress(); log.info("Add a session: " + SystemUtils.getRawAddress(remoteSocketAddress) + ":" + remoteSocketAddress.getPort()); + if (lastReolvedAddr != null + && !lastReolvedAddr.equals(remoteSocketAddress)) { + log.warn("Memcached node {} is resolved into {}.", lastReolvedAddr, + remoteSocketAddress); + // Remove and closed old resolved address. + Queue sessions = sessionMap.remove(lastReolvedAddr); + if (sessions != null) { + for (Session s : sessions) { + ((MemcachedSession) s).setAllowReconnect(false); + s.close(); + } + } + // updated resolve addr + addrWrapper.setResolvedSocketAddress(remoteSocketAddress); + } Queue sessions = this.sessionMap.get(remoteSocketAddress); if (sessions == null) { sessions = new ConcurrentLinkedQueue(); @@ -287,7 +307,9 @@ private void addMainSession(Session session) { } private void addStandbySession(Session session, - InetSocketAddress mainNodeAddress) { + InetSocketAddress mainNodeAddress, + InetSocketAddress lastResolvedMainAddr, + InetSocketAddressWrapper addrWrapper) { InetSocketAddress remoteSocketAddress = session .getRemoteSocketAddress(); log.info("Add a standby session: " @@ -295,6 +317,21 @@ private void addStandbySession(Session session, + remoteSocketAddress.getPort() + " for " + SystemUtils.getRawAddress(mainNodeAddress) + ":" + mainNodeAddress.getPort()); + if (lastResolvedMainAddr != null + && !lastResolvedMainAddr.equals(remoteSocketAddress)) { + log.warn("Memcached node {} is resolved into {}.", + lastResolvedMainAddr, remoteSocketAddress); + // Remove and closed old resolved address. + List sessions = standbySessionMap + .remove(lastResolvedMainAddr); + if (sessions != null) { + for (Session s : sessions) { + ((MemcachedSession) s).setAllowReconnect(false); + s.close(); + } + } + addrWrapper.setResolvedMainNodeSocketAddress(remoteSocketAddress); + } List sessions = this.standbySessionMap.get(mainNodeAddress); if (sessions == null) { sessions = new CopyOnWriteArrayList(); diff --git a/src/main/java/net/rubyeye/xmemcached/utils/InetSocketAddressWrapper.java b/src/main/java/net/rubyeye/xmemcached/utils/InetSocketAddressWrapper.java index 59b37bd45..44a710950 100644 --- a/src/main/java/net/rubyeye/xmemcached/utils/InetSocketAddressWrapper.java +++ b/src/main/java/net/rubyeye/xmemcached/utils/InetSocketAddressWrapper.java @@ -9,7 +9,7 @@ * */ public class InetSocketAddressWrapper { - private InetSocketAddress inetSocketAddress; + private volatile InetSocketAddress inetSocketAddress; private int order; // The address order in list private int weight; // The weight of this address private volatile String remoteAddressStr; @@ -19,7 +19,7 @@ public class InetSocketAddressWrapper { * Main memcached node address,if this is a main node,then this value is * null. */ - private InetSocketAddress mainNodeAddress; + private volatile InetSocketAddress mainNodeAddress; public InetSocketAddressWrapper(InetSocketAddress inetSocketAddress, int order, int weight, InetSocketAddress mainNodeAddress) { @@ -48,7 +48,23 @@ public final InetSocketAddress getInetSocketAddress() { } } - public final void setInetSocketAddress( + public final InetSocketAddress getResolvedSocketAddress() { + return this.inetSocketAddress; + } + + public final void setResolvedSocketAddress(InetSocketAddress addr) { + this.inetSocketAddress = addr; + } + + public final InetSocketAddress getResolvedMainNodeSocketAddress() { + return this.mainNodeAddress; + } + + public final void setResolvedMainNodeSocketAddress(InetSocketAddress addr) { + this.mainNodeAddress = addr; + } + + private final void setInetSocketAddress( InetSocketAddress inetSocketAddress) { this.inetSocketAddress = inetSocketAddress; if (inetSocketAddress != null) { @@ -77,7 +93,7 @@ public InetSocketAddress getMainNodeAddress() { } } - public void setMainNodeAddress(InetSocketAddress mainNodeAddress) { + private void setMainNodeAddress(InetSocketAddress mainNodeAddress) { this.mainNodeAddress = mainNodeAddress; if (mainNodeAddress != null) { this.mainNodeHostName = mainNodeAddress.getHostName(); From 90dd456f292b0dbd6f884b5300feea6fed3113af Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Thu, 22 Feb 2018 17:00:12 +0800 Subject: [PATCH 128/207] (fix) Failover mode cannot be initialized when memcached servers are down, close #73. --- .../impl/ClosedMemcachedTCPSession.java | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/rubyeye/xmemcached/impl/ClosedMemcachedTCPSession.java b/src/main/java/net/rubyeye/xmemcached/impl/ClosedMemcachedTCPSession.java index 0b7aca89a..26e4741f2 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/ClosedMemcachedTCPSession.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/ClosedMemcachedTCPSession.java @@ -4,7 +4,9 @@ import java.net.InetSocketAddress; import java.nio.ByteOrder; +import net.rubyeye.xmemcached.buffer.BufferAllocator; import net.rubyeye.xmemcached.networking.ClosedMemcachedSession; +import net.rubyeye.xmemcached.networking.MemcachedSession; import net.rubyeye.xmemcached.utils.InetSocketAddressWrapper; import com.google.code.yanf4j.core.Handler; @@ -17,9 +19,13 @@ * @author dennis * */ -public class ClosedMemcachedTCPSession implements ClosedMemcachedSession { +public class ClosedMemcachedTCPSession + implements + ClosedMemcachedSession, + MemcachedSession { private InetSocketAddressWrapper inetSocketAddressWrapper; private volatile boolean allowReconnect = true; + private volatile boolean authFailed = false; public ClosedMemcachedTCPSession( InetSocketAddressWrapper inetSocketAddressWrapper) { @@ -27,6 +33,27 @@ public ClosedMemcachedTCPSession( this.inetSocketAddressWrapper = inetSocketAddressWrapper; } + public void setBufferAllocator(BufferAllocator allocator) { + + } + + public void destroy() { + + } + + public void quit() { + + } + + public boolean isAuthFailed() { + return authFailed; + } + + public void setAuthFailed(boolean authFailed) { + this.authFailed = authFailed; + + } + public InetSocketAddressWrapper getInetSocketAddressWrapper() { return this.inetSocketAddressWrapper; } From 807a523f9787ef5bf04d8ecadca813d61ae0f9da Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Fri, 23 Feb 2018 10:44:06 +0800 Subject: [PATCH 129/207] (fix) docker-compose.yml --- README.md | 6 +++--- docker-compose.yml | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 278494d43..744aec384 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,14 @@ * [2.4.0](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.4.0) released, reduce CPU consumption when connecting to a lot of memcached servers. -* [2.3.2](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.2) released, some fixes and add compatibility for `KetamaMemcachedSessionLocator` with Gwhalin Memcached Java Client. +* [2.3.2](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.2) released, some fixes and add compatibility for `KetamaMemcachedSessionLocator` with Gwhalin Memcached Java Client. * [2.3.1](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.1) released, Adds `AWSElasticCacheClientBuilder` to build `AWSElasticCacheClient`. * [2.3.0](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.0) released, suppports [AWS ElasticCache Auto Discovery](http://docs.aws.amazon.com/AmazonElastiCache/latest/UserGuide/AutoDiscovery.html). ## Introduction XMemcached is a high performance, easy to use blocking multithreaded memcached client in java. - + It's nio based and was carefully turned to get top performance. * [Homepage](http://fnil.net/xmemcached/) @@ -33,7 +33,7 @@ Use [docker](https://docs.docker.com/engine/installation/) and [docker-compose]( ```sh $ cd xmemcached -$ docker-compose up +$ docker-compose up -d ``` Run unit tests: diff --git a/docker-compose.yml b/docker-compose.yml index 50a73211b..ab53550e3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,4 +5,6 @@ services: ports: - "22133:22133" memcached: - image: "memcached" + image: "memcached:1.5.5" + ports: + - "11211:11211" From 84c04b606af279154529a12d88ee363b55771b6e Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Fri, 23 Feb 2018 11:38:22 +0800 Subject: [PATCH 130/207] [maven-release-plugin] prepare release xmemcached-2.4.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f0cc9cb26..93a3b0626 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ 4.0.0 com.googlecode.xmemcached xmemcached - 2.4.1-SNAPSHOT + 2.4.1 xmemcached Extreme performance modern memcached client for java https://github.com/killme2008/xmemcached From 47cdda20b4cecefa9c7fdff860eafddffd5ab2de Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Fri, 23 Feb 2018 11:38:39 +0800 Subject: [PATCH 131/207] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 93a3b0626..4e8bfba64 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ 4.0.0 com.googlecode.xmemcached xmemcached - 2.4.1 + 2.4.2-SNAPSHOT xmemcached Extreme performance modern memcached client for java https://github.com/killme2008/xmemcached From ffbb6c36faeed2c01e67f47aa8d2f20f9558fcd3 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Fri, 23 Feb 2018 14:47:08 +0800 Subject: [PATCH 132/207] (feat) Adds an experiment option: xmemcached.string.fast.encoder, disabled by default. --- .../rubyeye/xmemcached/utils/ByteUtils.java | 15 ++- .../xmemcached/utils/CachedString.java | 102 ------------------ 2 files changed, 11 insertions(+), 106 deletions(-) delete mode 100644 src/main/java/net/rubyeye/xmemcached/utils/CachedString.java diff --git a/src/main/java/net/rubyeye/xmemcached/utils/ByteUtils.java b/src/main/java/net/rubyeye/xmemcached/utils/ByteUtils.java index 1138ff901..344a53dad 100644 --- a/src/main/java/net/rubyeye/xmemcached/utils/ByteUtils.java +++ b/src/main/java/net/rubyeye/xmemcached/utils/ByteUtils.java @@ -36,9 +36,8 @@ public final class ByteUtils { .forName(DEFAULT_CHARSET_NAME); public static final ByteBuffer SPLIT = ByteBuffer.wrap(Constants.CRLF); - public static final boolean ENABLE_CACHED_STRING_BYTES = Boolean - .valueOf(System.getProperty("xmemcached.string.bytes.cached.enable", - "false")); + public static final boolean ENABLE_FAST_STRING_ENCODER = Boolean.valueOf( + System.getProperty("xmemcached.string.fast.encoder", "false")); /** * if it is testing,check key argument even if use binary protocol. The user * must never change this value at all. @@ -76,7 +75,15 @@ public static final byte[] getBytes(String k) { if (k == null || k.length() == 0) { throw new IllegalArgumentException("Key must not be blank"); } - return FastStringEncoder.encodeUTF8(k); + if (!ENABLE_FAST_STRING_ENCODER) { + try { + return k.getBytes(DEFAULT_CHARSET_NAME); + } catch (UnsupportedEncodingException e) { + throw new IllegalStateException(e); + } + } else { + return FastStringEncoder.encodeUTF8(k); + } } public static final void setArguments(IoBuffer bb, Object... args) { diff --git a/src/main/java/net/rubyeye/xmemcached/utils/CachedString.java b/src/main/java/net/rubyeye/xmemcached/utils/CachedString.java deleted file mode 100644 index 72e933fb5..000000000 --- a/src/main/java/net/rubyeye/xmemcached/utils/CachedString.java +++ /dev/null @@ -1,102 +0,0 @@ -package net.rubyeye.xmemcached.utils; - -import java.lang.ref.Reference; -import java.lang.ref.ReferenceQueue; -import java.lang.ref.WeakReference; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -public class CachedString { - private static ConcurrentHashMap> table = new ConcurrentHashMap(); - static final ReferenceQueue rq = new ReferenceQueue(); - public static final int CLEAR_THRESHOLD = Integer.parseInt( - System.getProperty("xmemcached.string.bytes.cached.clear_threshold", - "1000")); - - public static byte[] getBytes(String s) { - if (s == null || s.length() == 0) { - return null; - } - byte[] bs = null; - Reference existingRef = table.get(s); - if (existingRef == null) { - clearCache(rq, table); - bs = s.getBytes(ByteUtils.DEFAULT_CHARSET); - existingRef = table.putIfAbsent(s, - new WeakReference(bs, rq)); - } - if (existingRef == null) { - return bs; - } - byte[] existingbs = existingRef.get(); - if (existingbs != null) { - return existingbs; - } - // entry died in the interim, do over - table.remove(s, existingRef); - return getBytes(s); - } - - static public void clearCache(ReferenceQueue rq, - ConcurrentHashMap> cache) { - if (cache.size() > CLEAR_THRESHOLD) { - // cleanup any dead entries - if (rq.poll() != null) { - while (rq.poll() != null) { - ; - } - for (Map.Entry> e : cache.entrySet()) { - Reference val = e.getValue(); - if (val != null && val.get() == null) { - cache.remove(e.getKey(), val); - } - } - } - } - } - - private static long testString(int keyLen) { - String k = getKey(keyLen); - long len = 0; - for (int i = 0; i < 1000; i++) { - // byte[] bs = k.getBytes(ByteUtils.DEFAULT_CHARSET); - // String nk = new String(bs, ByteUtils.DEFAULT_CHARSET); - byte[] bs = FastStringEncoder.encodeUTF8(k); - String nk = ByteUtils.getString(bs); - if (!k.equals(nk)) { - throw new RuntimeException(); - } - len += nk.length(); - } - return len; - } - - private static String getKey(int len) { - StringBuilder sb = new StringBuilder(); - String[] chars = {"a", "b", "c", "d", "e", "f", "g", "h"}; - int index = (int) Math.floor(Math.random() * 8); - for (int i = 0; i < len; i++) { - sb.append(chars[index]); - } - return sb.toString(); - } - - public static void main(String[] args) { - long sum = 0; - for (int i = 0; i < 10000; i++) { - sum += testString(8); - } - int[] keys = {8, 64, 128}; - - for (int k : keys) { - long start = System.currentTimeMillis(); - for (int i = 0; i < 100000; i++) { - sum += testString(k); - } - System.out.println("Key length=" + k + ", cost " - + (System.currentTimeMillis() - start) + " ms."); - } - System.out.println(sum); - System.out.println(table.size()); - } -} From a486e203f9c46d6e5d7d2fac0dca5c1db0ecd8d0 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Fri, 23 Feb 2018 14:53:16 +0800 Subject: [PATCH 133/207] [maven-release-plugin] prepare release xmemcached-2.4.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4e8bfba64..18036f274 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ 4.0.0 com.googlecode.xmemcached xmemcached - 2.4.2-SNAPSHOT + 2.4.2 xmemcached Extreme performance modern memcached client for java https://github.com/killme2008/xmemcached From ed368e3f249c2318f4be3ef15c2eb47807bf5d84 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Fri, 23 Feb 2018 14:55:09 +0800 Subject: [PATCH 134/207] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 18036f274..826ea15b0 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ 4.0.0 com.googlecode.xmemcached xmemcached - 2.4.2 + 2.4.3-SNAPSHOT xmemcached Extreme performance modern memcached client for java https://github.com/killme2008/xmemcached From ab75937ab47a08a95374e2743ab718f218579fb1 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Fri, 23 Feb 2018 18:13:06 +0800 Subject: [PATCH 135/207] (feat) update readme --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 744aec384..2eafaab2a 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,10 @@ ## News - +* [2.4.2](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.4.2) released, some bug fixes. * [2.4.0](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.4.0) released, reduce CPU consumption when connecting to a lot of memcached servers. * [2.3.2](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.2) released, some fixes and add compatibility for `KetamaMemcachedSessionLocator` with Gwhalin Memcached Java Client. * [2.3.1](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.1) released, Adds `AWSElasticCacheClientBuilder` to build `AWSElasticCacheClient`. -* [2.3.0](https://github.com/killme2008/xmemcached/releases/tag/xmemcached-2.3.0) released, suppports [AWS ElasticCache Auto Discovery](http://docs.aws.amazon.com/AmazonElastiCache/latest/UserGuide/AutoDiscovery.html). ## Introduction From 4c7d345e135496c8123e495f0bbdc9dd79990b32 Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Mon, 16 Apr 2018 11:04:34 +0800 Subject: [PATCH 136/207] (feat) format the code with google stype and adds plugin for it --- pom.xml | 18 + .../code/yanf4j/buffer/AbstractIoBuffer.java | 5067 ++++++++-------- .../yanf4j/buffer/BufferDataException.java | 94 +- .../yanf4j/buffer/CachedBufferAllocator.java | 566 +- .../google/code/yanf4j/buffer/IoBuffer.java | 2835 ++++----- .../code/yanf4j/buffer/IoBufferAllocator.java | 116 +- .../code/yanf4j/buffer/IoBufferHexDumper.java | 221 +- .../code/yanf4j/buffer/IoBufferWrapper.java | 1799 +++--- .../yanf4j/buffer/SimpleBufferAllocator.java | 219 +- .../google/code/yanf4j/buffer/package.html | 20 +- .../code/yanf4j/config/Configuration.java | 358 +- .../google/code/yanf4j/config/package.html | 20 +- .../google/code/yanf4j/core/CodecFactory.java | 46 +- .../google/code/yanf4j/core/Controller.java | 99 +- .../code/yanf4j/core/ControllerLifeCycle.java | 40 +- .../yanf4j/core/ControllerStateListener.java | 80 +- .../google/code/yanf4j/core/Dispatcher.java | 34 +- .../google/code/yanf4j/core/EventType.java | 32 +- .../com/google/code/yanf4j/core/Handler.java | 48 +- .../com/google/code/yanf4j/core/Session.java | 405 +- .../code/yanf4j/core/SessionConfig.java | 111 +- .../code/yanf4j/core/SessionManager.java | 54 +- .../google/code/yanf4j/core/SocketOption.java | 121 +- .../google/code/yanf4j/core/WriteMessage.java | 44 +- .../yanf4j/core/impl/AbstractController.java | 1020 ++-- .../yanf4j/core/impl/AbstractSession.java | 776 ++- .../core/impl/ByteBufferCodecFactory.java | 162 +- .../code/yanf4j/core/impl/FutureImpl.java | 307 +- .../code/yanf4j/core/impl/FutureLockImpl.java | 421 +- .../code/yanf4j/core/impl/HandlerAdapter.java | 73 +- .../code/yanf4j/core/impl/PoolDispatcher.java | 99 +- .../core/impl/StandardSocketOption.java | 387 +- .../core/impl/TextLineCodecFactory.java | 195 +- .../yanf4j/core/impl/WriteMessageImpl.java | 104 +- .../com/google/code/yanf4j/core/package.html | 20 +- .../google/code/yanf4j/nio/NioSession.java | 66 +- .../code/yanf4j/nio/NioSessionConfig.java | 56 +- .../code/yanf4j/nio/SelectionKeyHandler.java | 27 +- .../google/code/yanf4j/nio/TCPController.java | 292 +- .../yanf4j/nio/impl/AbstractNioSession.java | 591 +- .../code/yanf4j/nio/impl/NioController.java | 409 +- .../code/yanf4j/nio/impl/NioTCPSession.java | 585 +- .../google/code/yanf4j/nio/impl/Reactor.java | 1042 ++-- .../code/yanf4j/nio/impl/SelectorManager.java | 345 +- .../nio/impl/SocketChannelController.java | 195 +- .../com/google/code/yanf4j/nio/package.html | 20 +- .../code/yanf4j/statistics/Statistics.java | 110 +- .../statistics/impl/DefaultStatistics.java | 182 +- .../statistics/impl/SimpleStatistics.java | 465 +- .../code/yanf4j/statistics/package.html | 20 +- .../code/yanf4j/util/ByteBufferMatcher.java | 37 +- .../code/yanf4j/util/ByteBufferUtils.java | 354 +- .../code/yanf4j/util/CircularQueue.java | 703 ++- .../code/yanf4j/util/ConcurrentHashSet.java | 58 +- .../code/yanf4j/util/DispatcherFactory.java | 18 +- .../code/yanf4j/util/LinkedTransferQueue.java | 1607 +++-- .../google/code/yanf4j/util/MapBackedSet.java | 71 +- .../code/yanf4j/util/PropertyUtils.java | 66 +- .../code/yanf4j/util/ResourcesUtils.java | 390 +- .../code/yanf4j/util/SelectorFactory.java | 327 +- .../util/ShiftAndByteBufferMatcher.java | 145 +- .../yanf4j/util/ShiftOrByteBufferMatcher.java | 140 +- .../google/code/yanf4j/util/SimpleQueue.java | 48 +- .../google/code/yanf4j/util/SystemUtils.java | 313 +- .../code/yanf4j/util/TransferQueue.java | 232 +- .../code/yanf4j/util/WorkerThreadFactory.java | 97 +- .../com/google/code/yanf4j/util/package.html | 20 +- .../net/rubyeye/xmemcached/CASOperation.java | 44 +- .../rubyeye/xmemcached/CommandFactory.java | 522 +- .../java/net/rubyeye/xmemcached/Counter.java | 260 +- .../net/rubyeye/xmemcached/FlowControl.java | 74 +- .../net/rubyeye/xmemcached/GetsResponse.java | 116 +- .../net/rubyeye/xmemcached/HashAlgorithm.java | 452 +- .../net/rubyeye/xmemcached/KeyIterator.java | 91 +- .../net/rubyeye/xmemcached/KeyProvider.java | 34 +- .../rubyeye/xmemcached/MemcachedClient.java | 3600 ++++++----- .../xmemcached/MemcachedClientBuilder.java | 539 +- .../xmemcached/MemcachedClientCallable.java | 61 +- .../MemcachedClientStateListener.java | 93 +- .../xmemcached/MemcachedOptimizer.java | 77 +- .../xmemcached/MemcachedSessionLocator.java | 56 +- .../rubyeye/xmemcached/XMemcachedClient.java | 5323 ++++++++--------- .../xmemcached/XMemcachedClientBuilder.java | 874 ++- .../xmemcached/XMemcachedClientMBean.java | 101 +- .../net/rubyeye/xmemcached/auth/AuthInfo.java | 181 +- .../auth/AuthMemcachedConnectListener.java | 85 +- .../net/rubyeye/xmemcached/auth/AuthTask.java | 317 +- .../xmemcached/auth/PlainCallbackHandler.java | 79 +- .../net/rubyeye/xmemcached/auth/package.html | 20 +- .../xmemcached/aws/AWSElasticCacheClient.java | 604 +- .../aws/AWSElasticCacheClientBuilder.java | 220 +- .../net/rubyeye/xmemcached/aws/AWSUtils.java | 121 +- .../net/rubyeye/xmemcached/aws/CacheNode.java | 191 +- .../xmemcached/aws/ClusterConfigration.java | 105 +- .../xmemcached/aws/ConfigUpdateListener.java | 35 +- .../xmemcached/aws/ConfigurationPoller.java | 228 +- .../xmemcached/buffer/BufferAllocator.java | 21 +- .../buffer/CachedBufferAllocator.java | 552 +- .../rubyeye/xmemcached/buffer/IoBuffer.java | 61 +- .../buffer/SimpleBufferAllocator.java | 89 +- .../xmemcached/buffer/SimpleIoBuffer.java | 163 +- .../rubyeye/xmemcached/buffer/package.html | 21 +- .../codec/MemcachedCodecFactory.java | 53 +- .../xmemcached/codec/MemcachedDecoder.java | 82 +- .../xmemcached/codec/MemcachedEncoder.java | 22 +- .../net/rubyeye/xmemcached/codec/package.html | 20 +- .../xmemcached/command/AssocCommandAware.java | 7 +- .../command/BinaryCommandFactory.java | 317 +- .../rubyeye/xmemcached/command/Command.java | 576 +- .../xmemcached/command/CommandType.java | 10 +- .../command/KestrelCommandFactory.java | 249 +- .../command/MapReturnValueAware.java | 5 +- .../command/MergeCommandsAware.java | 8 +- .../xmemcached/command/OperationStatus.java | 5 +- .../command/ServerAddressAware.java | 11 +- .../xmemcached/command/StoreCommand.java | 28 +- .../command/TextCommandFactory.java | 409 +- .../xmemcached/command/VerbosityCommand.java | 26 +- .../command/binary/BaseBinaryCommand.java | 780 ++- .../BinaryAWSElasticCacheConfigCommand.java | 115 +- .../binary/BinaryAppendPrependCommand.java | 79 +- .../BinaryAuthListMechanismsCommand.java | 129 +- .../binary/BinaryAuthStartCommand.java | 123 +- .../command/binary/BinaryAuthStepCommand.java | 121 +- .../command/binary/BinaryCASCommand.java | 65 +- .../command/binary/BinaryDecodeStatus.java | 35 +- .../command/binary/BinaryDeleteCommand.java | 112 +- .../command/binary/BinaryFlushAllCommand.java | 108 +- .../binary/BinaryGetAndTouchCommand.java | 85 +- .../command/binary/BinaryGetCommand.java | 284 +- .../command/binary/BinaryGetMultiCommand.java | 348 +- .../command/binary/BinaryIncrDecrCommand.java | 155 +- .../command/binary/BinaryNoopCommand.java | 39 +- .../command/binary/BinaryQuitCommand.java | 156 +- .../command/binary/BinarySetMultiCommand.java | 209 +- .../command/binary/BinaryStatsCommand.java | 269 +- .../command/binary/BinaryStoreCommand.java | 92 +- .../command/binary/BinaryTouchCommand.java | 85 +- .../binary/BinaryVerbosityCommand.java | 107 +- .../command/binary/BinaryVersionCommand.java | 139 +- .../xmemcached/command/binary/OpCode.java | 546 +- .../command/binary/ResponseStatus.java | 501 +- .../xmemcached/command/binary/package.html | 20 +- .../command/kestrel/KestrelDeleteCommand.java | 77 +- .../kestrel/KestrelFlushAllCommand.java | 74 +- .../command/kestrel/KestrelGetCommand.java | 105 +- .../command/kestrel/KestrelSetCommand.java | 83 +- .../xmemcached/command/kestrel/package.html | 20 +- .../rubyeye/xmemcached/command/package.html | 21 +- .../TextAWSElasticCacheConfigCommand.java | 135 +- .../command/text/TextCASCommand.java | 140 +- .../command/text/TextCacheDumpCommand.java | 93 +- .../command/text/TextDeleteCommand.java | 148 +- .../command/text/TextFlushAllCommand.java | 146 +- .../command/text/TextGetCommand.java | 527 +- .../command/text/TextGetMultiCommand.java | 56 +- .../command/text/TextGetOneCommand.java | 98 +- .../command/text/TextIncrDecrCommand.java | 145 +- .../command/text/TextQuitCommand.java | 67 +- .../command/text/TextStatsCommand.java | 142 +- .../command/text/TextStoreCommand.java | 338 +- .../command/text/TextTouchCommand.java | 159 +- .../command/text/TextVerbosityCommand.java | 108 +- .../command/text/TextVersionCommand.java | 96 +- .../xmemcached/command/text/package.html | 20 +- .../exception/MemcachedClientException.java | 44 +- .../exception/MemcachedDecodeException.java | 26 +- .../exception/MemcachedException.java | 41 +- .../exception/MemcachedServerException.java | 44 +- .../exception/NoValueException.java | 75 +- .../exception/UnknownCommandException.java | 41 +- .../rubyeye/xmemcached/exception/package.html | 20 +- .../impl/AbstractMemcachedSessionLocator.java | 42 +- .../impl/ArrayMemcachedSessionLocator.java | 245 +- .../impl/ClosedMemcachedTCPSession.java | 453 +- .../xmemcached/impl/ConnectFuture.java | 47 +- .../xmemcached/impl/DefaultKeyProvider.java | 38 +- .../impl/ElectionMemcachedSessionLocator.java | 135 +- .../impl/FlowControlLinkedTransferQueue.java | 319 +- .../impl/KetamaMemcachedSessionLocator.java | 521 +- .../xmemcached/impl/KeyIteratorImpl.java | 140 +- .../LibmemcachedMemcachedSessionLocator.java | 209 +- .../MemcachedClientStateListenerAdapter.java | 90 +- .../xmemcached/impl/MemcachedConnector.java | 1381 ++--- .../xmemcached/impl/MemcachedHandler.java | 525 +- .../impl/MemcachedSessionComparator.java | 33 +- .../xmemcached/impl/MemcachedTCPSession.java | 471 +- .../rubyeye/xmemcached/impl/Optimizer.java | 1260 ++-- .../xmemcached/impl/OptimizerMBean.java | 46 +- .../impl/PHPMemcacheSessionLocator.java | 194 +- .../impl/RandomMemcachedSessionLocaltor.java | 76 +- .../xmemcached/impl/ReconnectRequest.java | 184 +- .../RoundRobinMemcachedSessionLocator.java | 108 +- .../net/rubyeye/xmemcached/impl/package.html | 21 +- .../rubyeye/xmemcached/monitor/Constants.java | 103 +- .../monitor/MemcachedClientNameHolder.java | 48 +- .../xmemcached/monitor/StatisticsHandler.java | 257 +- .../monitor/StatisticsHandlerMBean.java | 72 +- .../monitor/XMemcachedMbeanServer.java | 295 +- .../rubyeye/xmemcached/monitor/package.html | 20 +- .../networking/ClosedMemcachedSession.java | 41 +- .../xmemcached/networking/Connector.java | 206 +- .../networking/MemcachedSession.java | 40 +- .../MemcachedSessionConnectListener.java | 27 +- .../xmemcached/networking/package.html | 20 +- .../java/net/rubyeye/xmemcached/package.html | 21 +- .../BaseSerializingTranscoder.java | 664 +- .../xmemcached/transcoders/CachedData.java | 294 +- .../transcoders/CompressionMode.java | 36 +- .../transcoders/IntegerTranscoder.java | 141 +- .../transcoders/LongTranscoder.java | 134 +- .../transcoders/PrimitiveTypeTranscoder.java | 35 +- .../transcoders/SerializingTranscoder.java | 467 +- .../transcoders/StringTranscoder.java | 76 +- .../transcoders/TokyoTyrantTranscoder.java | 186 +- .../xmemcached/transcoders/Transcoder.java | 139 +- .../transcoders/TranscoderUtils.java | 195 +- .../transcoders/WhalinTranscoder.java | 501 +- .../transcoders/WhalinV1Transcoder.java | 592 +- .../xmemcached/transcoders/package.html | 20 +- .../rubyeye/xmemcached/utils/AddrUtil.java | 237 +- .../rubyeye/xmemcached/utils/ByteUtils.java | 984 ++- .../xmemcached/utils/FastStringEncoder.java | 220 +- .../utils/InetSocketAddressWrapper.java | 184 +- .../xmemcached/utils/OpaqueGenerater.java | 90 +- .../rubyeye/xmemcached/utils/Protocol.java | 32 +- .../utils/XMemcachedClientFactoryBean.java | 533 +- .../net/rubyeye/xmemcached/utils/package.html | 20 +- .../code/yanf4j/test/unittest/Main.java | 24 +- .../code/yanf4j/test/unittest/buffer/Bar.java | 80 +- .../code/yanf4j/test/unittest/buffer/Foo.java | 84 +- .../test/unittest/buffer/IoBufferTest.java | 2260 ++++--- .../unittest/config/ConfigurationTest.java | 97 +- .../unittest/core/SocketOptionUnitTest.java | 51 +- .../core/impl/AbstractControllerUnitTest.java | 273 +- .../impl/ByteBufferCodecFactoryUnitTest.java | 88 +- .../core/impl/FutureImplUnitTest.java | 201 +- .../core/impl/FutureLockImplUnitTest.java | 198 +- .../core/impl/PoolDispatcherUnitTest.java | 136 +- .../impl/TextLineCodecFactoryUnitTest.java | 88 +- .../nio/impl/MockSelectableChannel.java | 106 +- .../unittest/nio/impl/MockSelectionKey.java | 82 +- .../unittest/nio/impl/ReactorUnitTest.java | 399 +- .../nio/impl/SelectorManagerUnitTest.java | 160 +- .../statistics/SimpleStatisticsTest.java | 225 +- .../unittest/utils/ByteBufferMatcherTest.java | 84 +- .../unittest/utils/ByteBufferUtilsTest.java | 267 +- .../utils/DispatcherFactoryUnitTest.java | 63 +- .../unittest/utils/FastStringEncoderTest.java | 99 +- .../yanf4j/test/unittest/utils/QueueTest.java | 202 +- .../utils/ShiftAndByteBufferMatcherTest.java | 11 +- .../utils/ShiftOrByteBufferMatcherTest.java | 11 +- .../unittest/utils/SystemUtilsUniTest.java | 31 +- .../example/BinaryProtocolExample.java | 101 +- .../xmemcached/example/CASExample.java | 135 +- .../MemcachedStateListenerExample.java | 156 +- .../xmemcached/example/SASLExample.java | 166 +- .../xmemcached/example/SimpleExample.java | 170 +- .../xmemcached/example/SpringExample.java | 55 +- .../xmemcached/helper/AbstractChecker.java | 657 +- .../xmemcached/helper/BlankKeyChecker.java | 16 +- .../xmemcached/helper/ExceptionChecker.java | 5 +- .../xmemcached/helper/InValidKeyChecker.java | 19 +- .../xmemcached/helper/MockTranscoder.java | 62 +- .../xmemcached/helper/TooLongKeyChecker.java | 29 +- .../xmemcached/helper/TranscoderChecker.java | 22 +- .../pressure/MemcachedClientPressureTest.java | 267 +- .../unittest/AWSElasticCacheClientIT.java | 345 +- .../unittest/BinaryMemcachedClientIT.java | 256 +- .../ConnectionPoolMemcachedClientIT.java | 295 +- .../ConsistentHashMemcachedClientIT.java | 45 +- .../test/unittest/FailureModeUnitTest.java | 685 ++- .../test/unittest/KestrelClientIT.java | 472 +- .../test/unittest/MockMemcachedSession.java | 85 +- .../xmemcached/test/unittest/MockSession.java | 219 +- .../StandardHashMemcachedClientIT.java | 368 +- .../test/unittest/XMemcachedClientIT.java | 2478 ++++---- .../XMemcachedClientWithKeyProviderIT.java | 131 +- .../AbstractBufferAllocatorUnitTest.java | 153 +- .../buffer/BufferAllocatorTestSuite.java | 17 +- .../buffer/CachedBufferAllocatorUnitTest.java | 10 +- .../buffer/SimpleBufferAllocatorUnitTest.java | 12 +- .../codec/MemcachedDecoderUnitTest.java | 39 +- .../codec/MemcachedEncoderUnitTest.java | 19 +- .../binary/BaseBinaryCommandUnitTest.java | 73 +- .../BinaryAppendPrependCommandUnitTest.java | 103 +- .../binary/BinaryCASCommandUnitTest.java | 71 +- .../binary/BinaryCommandAllTests.java | 30 +- .../binary/BinaryDeleteCommandUnitTest.java | 64 +- .../BinaryGetAndTouchCommandUnitTest.java | 94 +- .../binary/BinaryGetCommandUnitTest.java | 70 +- .../binary/BinaryGetMultiCommandUnitTest.java | 134 +- .../binary/BinaryIncrDecrUnitTest.java | 115 +- .../binary/BinaryStatsCommandUnitTest.java | 80 +- .../binary/BinaryStoreCommandUnitTest.java | 186 +- .../binary/BinaryTouchCommandUnitTest.java | 78 +- .../factory/TextCommandFactoryTest.java | 186 +- .../text/BaseTextCommandUnitTest.java | 82 +- .../commands/text/TextCommandsAllTests.java | 29 +- .../text/TextDeleteCommandUnitTest.java | 49 +- .../text/TextFlushAllCommandUnitTest.java | 76 +- .../text/TextGetMultiCommandUnitTest.java | 148 +- .../text/TextGetOneCommandUnitTest.java | 116 +- .../text/TextIncrDecrCommandUnitTest.java | 115 +- .../text/TextStatsCommandUnitTest.java | 57 +- .../text/TextStoreCommandUnitTest.java | 276 +- .../text/TextTouchCommandUnitTest.java | 45 +- .../text/TextVerbositylCommandUnitTest.java | 40 +- .../text/TextVersionCommandUnitTest.java | 34 +- ...stractMemcachedSessionLocatorUnitTest.java | 66 +- .../ArrayMemcachedSessionLocatorUnitTest.java | 256 +- ...torGwhalinMemcachedJavaClientUnitTest.java | 205 +- ...ocatorNginxUpstreamConsistentUnitTest.java | 454 +- ...KetamaMemcachedSessionLocatorUnitTest.java | 196 +- .../impl/MemcachedClientStateListenerIT.java | 159 +- .../impl/MemcachedHandlerUnitTest.java | 166 +- .../MemcachedSessionComparatorUnitTest.java | 365 +- .../MockMemcachedClientStateListener.java | 84 +- .../test/unittest/impl/OptimizerTest.java | 568 +- ...dRobinMemcachedSessionLocatorUnitTest.java | 85 +- .../unittest/impl/SessionLocatorTest.java | 88 +- .../MockDecodeTimeoutBinaryGetOneCommand.java | 36 +- .../MockDecodeTimeoutTextGetOneCommand.java | 33 +- .../MockEncodeTimeoutBinaryGetCommand.java | 32 +- .../MockEncodeTimeoutTextGetOneCommand.java | 31 +- .../mock/MockErrorBinaryGetOneCommand.java | 38 +- .../test/unittest/mock/MockErrorCommand.java | 2 +- .../mock/MockErrorTextGetOneCommand.java | 39 +- .../MemcachedClientHolderUnitTest.java | 89 +- .../test/unittest/monitor/Mock.java | 6 +- .../test/unittest/monitor/MockMBean.java | 2 +- .../monitor/StatisticsHandlerUnitTest.java | 65 +- .../XMemcachedMBeanServerUnitTest.java | 56 +- .../BaseSerializingTranscoderTest.java | 275 +- .../transcoder/BaseTranscoderCase.java | 360 +- .../unittest/transcoder/CachedDataTest.java | 41 +- .../transcoder/IntegerTranscoderTest.java | 57 +- .../transcoder/LongTranscoderTest.java | 57 +- .../transcoder/PrimitiveAsStringUnitTest.java | 162 +- .../transcoder/SerializingTranscoderTest.java | 238 +- .../TokyoTyrantTranscoderUnitTest.java | 254 +- .../transcoder/TranscoderAllTests.java | 31 +- .../transcoder/TranscoderUtilsTest.java | 131 +- .../transcoder/WhalinTranscoderTest.java | 214 +- .../transcoder/WhalinV1TranscoderTest.java | 62 +- .../test/unittest/utils/AddrUtilTest.java | 244 +- .../utils/OpaqueGeneraterUnitTest.java | 78 +- .../utils/XMemcachedClientFactoryBeanIT.java | 81 +- 348 files changed, 40405 insertions(+), 43700 deletions(-) diff --git a/pom.xml b/pom.xml index 826ea15b0..f3d20d47e 100644 --- a/pom.xml +++ b/pom.xml @@ -109,6 +109,23 @@ + + + net.revelc.code.formatter + formatter-maven-plugin + 2.7.2 + + ${project.basedir}/eclipse-java-google-style.xml + CRLF + + + + + format + + + + org.codehaus.mojo build-helper-maven-plugin @@ -245,6 +262,7 @@ + org.apache.maven.plugins maven-javadoc-plugin diff --git a/src/main/java/com/google/code/yanf4j/buffer/AbstractIoBuffer.java b/src/main/java/com/google/code/yanf4j/buffer/AbstractIoBuffer.java index 3ec79c739..116ce9a5e 100644 --- a/src/main/java/com/google/code/yanf4j/buffer/AbstractIoBuffer.java +++ b/src/main/java/com/google/code/yanf4j/buffer/AbstractIoBuffer.java @@ -1,2573 +1,2494 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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 com.google.code.yanf4j.buffer; - -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.ObjectStreamClass; -import java.io.OutputStream; -import java.io.StreamCorruptedException; -import java.nio.BufferOverflowException; -import java.nio.BufferUnderflowException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.CharBuffer; -import java.nio.DoubleBuffer; -import java.nio.FloatBuffer; -import java.nio.IntBuffer; -import java.nio.LongBuffer; -import java.nio.ShortBuffer; -import java.nio.charset.CharacterCodingException; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CharsetEncoder; -import java.nio.charset.CoderResult; -import java.util.EnumSet; -import java.util.Set; - -/** - * A base implementation of {@link IoBuffer}. This implementation assumes that - * {@link IoBuffer#buf()} always returns a correct NIO {@link ByteBuffer} - * instance. Most implementations could extend this class and implement their - * own buffer management mechanism. - * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev: 748210 $, $Date: 2009-02-26 18:05:40 +0100 (Thu, 26 Feb 2009) - * $ - * @see IoBufferAllocator - */ -public abstract class AbstractIoBuffer extends IoBuffer { - /** Tells if a buffer has been created from an existing buffer */ - private final boolean derived; - - /** A flag set to true if the buffer can extend automatically */ - private boolean autoExpand; - - /** A flag set to true if the buffer can shrink automatically */ - private boolean autoShrink; - - /** Tells if a buffer can be expanded */ - private boolean recapacityAllowed = true; - - /** The minimum number of bytes the IoBuffer can hold */ - private int minimumCapacity; - - /** A mask for a byte */ - private static final long BYTE_MASK = 0xFFL; - - /** A mask for a short */ - private static final long SHORT_MASK = 0xFFFFL; - - /** A mask for an int */ - private static final long INT_MASK = 0xFFFFFFFFL; - - /** - * We don't have any access to Buffer.markValue(), so we need to track it - * down, which will cause small extra overhead. - */ - private int mark = -1; - - /** - * Creates a new parent buffer. - * - * @param allocator - * The allocator to use to create new buffers - * @param initialCapacity - * The initial buffer capacity when created - */ - protected AbstractIoBuffer(IoBufferAllocator allocator, - int initialCapacity) { - setAllocator(allocator); - this.recapacityAllowed = true; - this.derived = false; - this.minimumCapacity = initialCapacity; - } - - /** - * Creates a new derived buffer. A derived buffer uses an existing buffer - * properties - the allocator and capacity -. - * - * @param parent - * The buffer we get the properties from - */ - protected AbstractIoBuffer(AbstractIoBuffer parent) { - setAllocator(parent.getAllocator()); - this.recapacityAllowed = false; - this.derived = true; - this.minimumCapacity = parent.minimumCapacity; - } - - /** - * {@inheritDoc} - */ - @Override - public final boolean isDirect() { - return buf().isDirect(); - } - - /** - * {@inheritDoc} - */ - @Override - public final boolean isReadOnly() { - return buf().isReadOnly(); - } - - /** - * Sets the underlying NIO buffer instance. - * - * @param newBuf - * The buffer to store within this IoBuffer - */ - protected abstract void buf(ByteBuffer newBuf); - - /** - * {@inheritDoc} - */ - @Override - public final int minimumCapacity() { - return minimumCapacity; - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer minimumCapacity(int minimumCapacity) { - if (minimumCapacity < 0) { - throw new IllegalArgumentException( - "minimumCapacity: " + minimumCapacity); - } - this.minimumCapacity = minimumCapacity; - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final int capacity() { - return buf().capacity(); - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer capacity(int newCapacity) { - if (!recapacityAllowed) { - throw new IllegalStateException( - "Derived buffers and their parent can't be expanded."); - } - - // Allocate a new buffer and transfer all settings to it. - if (newCapacity > capacity()) { - // Expand: - // // Save the state. - int pos = position(); - int limit = limit(); - ByteOrder bo = order(); - - // // Reallocate. - ByteBuffer oldBuf = buf(); - ByteBuffer newBuf = getAllocator().allocateNioBuffer(newCapacity, - isDirect()); - oldBuf.clear(); - newBuf.put(oldBuf); - buf(newBuf); - - // // Restore the state. - buf().limit(limit); - if (mark >= 0) { - buf().position(mark); - buf().mark(); - } - buf().position(pos); - buf().order(bo); - } - - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final boolean isAutoExpand() { - return autoExpand && recapacityAllowed; - } - - /** - * {@inheritDoc} - */ - @Override - public final boolean isAutoShrink() { - return autoShrink && recapacityAllowed; - } - - /** - * {@inheritDoc} - */ - @Override - public final boolean isDerived() { - return derived; - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer setAutoExpand(boolean autoExpand) { - if (!recapacityAllowed) { - throw new IllegalStateException( - "Derived buffers and their parent can't be expanded."); - } - this.autoExpand = autoExpand; - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer setAutoShrink(boolean autoShrink) { - if (!recapacityAllowed) { - throw new IllegalStateException( - "Derived buffers and their parent can't be shrinked."); - } - this.autoShrink = autoShrink; - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer expand(int expectedRemaining) { - return expand(position(), expectedRemaining, false); - } - - private IoBuffer expand(int expectedRemaining, boolean autoExpand) { - return expand(position(), expectedRemaining, autoExpand); - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer expand(int pos, int expectedRemaining) { - return expand(pos, expectedRemaining, false); - } - - private IoBuffer expand(int pos, int expectedRemaining, - boolean autoExpand) { - if (!recapacityAllowed) { - throw new IllegalStateException( - "Derived buffers and their parent can't be expanded."); - } - - int end = pos + expectedRemaining; - int newCapacity; - if (autoExpand) { - newCapacity = IoBuffer.normalizeCapacity(end); - } else { - newCapacity = end; - } - if (newCapacity > capacity()) { - // The buffer needs expansion. - capacity(newCapacity); - } - - if (end > limit()) { - // We call limit() directly to prevent StackOverflowError - buf().limit(end); - } - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer shrink() { - - if (!recapacityAllowed) { - throw new IllegalStateException( - "Derived buffers and their parent can't be expanded."); - } - - int position = position(); - int capacity = capacity(); - int limit = limit(); - if (capacity == limit) { - return this; - } - - int newCapacity = capacity; - int minCapacity = Math.max(minimumCapacity, limit); - for (;;) { - if (newCapacity >>> 1 < minCapacity) { - break; - } - newCapacity >>>= 1; - } - - newCapacity = Math.max(minCapacity, newCapacity); - - if (newCapacity == capacity) { - return this; - } - - // Shrink and compact: - // // Save the state. - ByteOrder bo = order(); - - // // Reallocate. - ByteBuffer oldBuf = buf(); - ByteBuffer newBuf = getAllocator().allocateNioBuffer(newCapacity, - isDirect()); - oldBuf.position(0); - oldBuf.limit(limit); - newBuf.put(oldBuf); - buf(newBuf); - - // // Restore the state. - buf().position(position); - buf().limit(limit); - buf().order(bo); - mark = -1; - - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final int position() { - return buf().position(); - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer position(int newPosition) { - autoExpand(newPosition, 0); - buf().position(newPosition); - if (mark > newPosition) { - mark = -1; - } - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final int limit() { - return buf().limit(); - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer limit(int newLimit) { - autoExpand(newLimit, 0); - buf().limit(newLimit); - if (mark > newLimit) { - mark = -1; - } - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer mark() { - buf().mark(); - mark = position(); - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final int markValue() { - return mark; - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer reset() { - buf().reset(); - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer clear() { - buf().clear(); - mark = -1; - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer sweep() { - clear(); - return fillAndReset(remaining()); - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer sweep(byte value) { - clear(); - return fillAndReset(value, remaining()); - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer flip() { - buf().flip(); - mark = -1; - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer rewind() { - buf().rewind(); - mark = -1; - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final int remaining() { - return limit() - position(); - } - - /** - * {@inheritDoc} - */ - @Override - public final boolean hasRemaining() { - return limit() > position(); - } - - /** - * {@inheritDoc} - */ - @Override - public final byte get() { - return buf().get(); - } - - /** - * {@inheritDoc} - */ - @Override - public final short getUnsigned() { - return (short) (get() & 0xff); - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer put(byte b) { - autoExpand(1); - buf().put(b); - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final byte get(int index) { - return buf().get(index); - } - - /** - * {@inheritDoc} - */ - @Override - public final short getUnsigned(int index) { - return (short) (get(index) & 0xff); - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer put(int index, byte b) { - autoExpand(index, 1); - buf().put(index, b); - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer get(byte[] dst, int offset, int length) { - buf().get(dst, offset, length); - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer put(ByteBuffer src) { - autoExpand(src.remaining()); - buf().put(src); - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer put(byte[] src, int offset, int length) { - autoExpand(length); - buf().put(src, offset, length); - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer compact() { - int remaining = remaining(); - int capacity = capacity(); - - if (capacity == 0) { - return this; - } - - if (isAutoShrink() && remaining <= capacity >>> 2 - && capacity > minimumCapacity) { - int newCapacity = capacity; - int minCapacity = Math.max(minimumCapacity, remaining << 1); - for (;;) { - if (newCapacity >>> 1 < minCapacity) { - break; - } - newCapacity >>>= 1; - } - - newCapacity = Math.max(minCapacity, newCapacity); - - if (newCapacity == capacity) { - return this; - } - - // Shrink and compact: - // // Save the state. - ByteOrder bo = order(); - - // // Sanity check. - if (remaining > newCapacity) { - throw new IllegalStateException( - "The amount of the remaining bytes is greater than " - + "the new capacity."); - } - - // // Reallocate. - ByteBuffer oldBuf = buf(); - ByteBuffer newBuf = getAllocator().allocateNioBuffer(newCapacity, - isDirect()); - newBuf.put(oldBuf); - buf(newBuf); - - // // Restore the state. - buf().order(bo); - } else { - buf().compact(); - } - mark = -1; - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final ByteOrder order() { - return buf().order(); - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer order(ByteOrder bo) { - buf().order(bo); - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final char getChar() { - return buf().getChar(); - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer putChar(char value) { - autoExpand(2); - buf().putChar(value); - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final char getChar(int index) { - return buf().getChar(index); - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer putChar(int index, char value) { - autoExpand(index, 2); - buf().putChar(index, value); - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final CharBuffer asCharBuffer() { - return buf().asCharBuffer(); - } - - /** - * {@inheritDoc} - */ - @Override - public final short getShort() { - return buf().getShort(); - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer putShort(short value) { - autoExpand(2); - buf().putShort(value); - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final short getShort(int index) { - return buf().getShort(index); - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer putShort(int index, short value) { - autoExpand(index, 2); - buf().putShort(index, value); - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final ShortBuffer asShortBuffer() { - return buf().asShortBuffer(); - } - - /** - * {@inheritDoc} - */ - @Override - public final int getInt() { - return buf().getInt(); - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer putInt(int value) { - autoExpand(4); - buf().putInt(value); - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final int getInt(int index) { - return buf().getInt(index); - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer putInt(int index, int value) { - autoExpand(index, 4); - buf().putInt(index, value); - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final IntBuffer asIntBuffer() { - return buf().asIntBuffer(); - } - - /** - * {@inheritDoc} - */ - @Override - public final long getLong() { - return buf().getLong(); - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer putLong(long value) { - autoExpand(8); - buf().putLong(value); - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final long getLong(int index) { - return buf().getLong(index); - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer putLong(int index, long value) { - autoExpand(index, 8); - buf().putLong(index, value); - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final LongBuffer asLongBuffer() { - return buf().asLongBuffer(); - } - - /** - * {@inheritDoc} - */ - @Override - public final float getFloat() { - return buf().getFloat(); - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer putFloat(float value) { - autoExpand(4); - buf().putFloat(value); - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final float getFloat(int index) { - return buf().getFloat(index); - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer putFloat(int index, float value) { - autoExpand(index, 4); - buf().putFloat(index, value); - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final FloatBuffer asFloatBuffer() { - return buf().asFloatBuffer(); - } - - /** - * {@inheritDoc} - */ - @Override - public final double getDouble() { - return buf().getDouble(); - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer putDouble(double value) { - autoExpand(8); - buf().putDouble(value); - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final double getDouble(int index) { - return buf().getDouble(index); - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer putDouble(int index, double value) { - autoExpand(index, 8); - buf().putDouble(index, value); - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public final DoubleBuffer asDoubleBuffer() { - return buf().asDoubleBuffer(); - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer asReadOnlyBuffer() { - recapacityAllowed = false; - return asReadOnlyBuffer0(); - } - - /** - * Implement this method to return the unexpandable read only version of - * this buffer. - */ - protected abstract IoBuffer asReadOnlyBuffer0(); - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer duplicate() { - recapacityAllowed = false; - return duplicate0(); - } - - /** - * Implement this method to return the unexpandable duplicate of this - * buffer. - */ - protected abstract IoBuffer duplicate0(); - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer slice() { - recapacityAllowed = false; - return slice0(); - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer getSlice(int index, int length) { - if (length < 0) { - throw new IllegalArgumentException("length: " + length); - } - - int limit = limit(); - - if (index > limit) { - throw new IllegalArgumentException("index: " + index); - } - - int endIndex = index + length; - - if (capacity() < endIndex) { - throw new IndexOutOfBoundsException("index + length (" + endIndex - + ") is greater " + "than capacity (" + capacity() + ")."); - } - - clear(); - position(index); - limit(endIndex); - - IoBuffer slice = slice(); - position(index); - limit(limit); - return slice; - } - - /** - * {@inheritDoc} - */ - @Override - public final IoBuffer getSlice(int length) { - if (length < 0) { - throw new IllegalArgumentException("length: " + length); - } - int pos = position(); - int limit = limit(); - int nextPos = pos + length; - if (limit < nextPos) { - throw new IndexOutOfBoundsException("position + length (" + nextPos - + ") is greater " + "than limit (" + limit + ")."); - } - - limit(pos + length); - IoBuffer slice = slice(); - position(nextPos); - limit(limit); - return slice; - } - - /** - * Implement this method to return the unexpandable slice of this buffer. - */ - protected abstract IoBuffer slice0(); - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - int h = 1; - int p = position(); - for (int i = limit() - 1; i >= p; i--) { - h = 31 * h + get(i); - } - return h; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean equals(Object o) { - if (!(o instanceof IoBuffer)) { - return false; - } - - IoBuffer that = (IoBuffer) o; - if (this.remaining() != that.remaining()) { - return false; - } - - int p = this.position(); - for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--) { - byte v1 = this.get(i); - byte v2 = that.get(j); - if (v1 != v2) { - return false; - } - } - return true; - } - - /** - * {@inheritDoc} - */ - public int compareTo(IoBuffer that) { - int n = this.position() + Math.min(this.remaining(), that.remaining()); - for (int i = this.position(), j = that.position(); i < n; i++, j++) { - byte v1 = this.get(i); - byte v2 = that.get(j); - if (v1 == v2) { - continue; - } - if (v1 < v2) { - return -1; - } - - return +1; - } - return this.remaining() - that.remaining(); - } - - /** - * {@inheritDoc} - */ - @Override - public String toString() { - StringBuilder buf = new StringBuilder(); - if (isDirect()) { - buf.append("DirectBuffer"); - } else { - buf.append("HeapBuffer"); - } - buf.append("[pos="); - buf.append(position()); - buf.append(" lim="); - buf.append(limit()); - buf.append(" cap="); - buf.append(capacity()); - buf.append(": "); - buf.append(getHexDump(16)); - buf.append(']'); - return buf.toString(); - } - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer get(byte[] dst) { - return get(dst, 0, dst.length); - } - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer put(IoBuffer src) { - return put(src.buf()); - } - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer put(byte[] src) { - return put(src, 0, src.length); - } - - /** - * {@inheritDoc} - */ - @Override - public int getUnsignedShort() { - return getShort() & 0xffff; - } - - /** - * {@inheritDoc} - */ - @Override - public int getUnsignedShort(int index) { - return getShort(index) & 0xffff; - } - - /** - * {@inheritDoc} - */ - @Override - public long getUnsignedInt() { - return getInt() & 0xffffffffL; - } - - /** - * {@inheritDoc} - */ - @Override - public int getMediumInt() { - byte b1 = get(); - byte b2 = get(); - byte b3 = get(); - if (ByteOrder.BIG_ENDIAN.equals(order())) { - return getMediumInt(b1, b2, b3); - } else { - return getMediumInt(b3, b2, b1); - } - } - - /** - * {@inheritDoc} - */ - @Override - public int getUnsignedMediumInt() { - int b1 = getUnsigned(); - int b2 = getUnsigned(); - int b3 = getUnsigned(); - if (ByteOrder.BIG_ENDIAN.equals(order())) { - return b1 << 16 | b2 << 8 | b3; - } else { - return b3 << 16 | b2 << 8 | b1; - } - } - - /** - * {@inheritDoc} - */ - @Override - public int getMediumInt(int index) { - byte b1 = get(index); - byte b2 = get(index + 1); - byte b3 = get(index + 2); - if (ByteOrder.BIG_ENDIAN.equals(order())) { - return getMediumInt(b1, b2, b3); - } else { - return getMediumInt(b3, b2, b1); - } - } - - /** - * {@inheritDoc} - */ - @Override - public int getUnsignedMediumInt(int index) { - int b1 = getUnsigned(index); - int b2 = getUnsigned(index + 1); - int b3 = getUnsigned(index + 2); - if (ByteOrder.BIG_ENDIAN.equals(order())) { - return b1 << 16 | b2 << 8 | b3; - } else { - return b3 << 16 | b2 << 8 | b1; - } - } - - /** - * {@inheritDoc} - */ - private int getMediumInt(byte b1, byte b2, byte b3) { - int ret = b1 << 16 & 0xff0000 | b2 << 8 & 0xff00 | b3 & 0xff; - // Check to see if the medium int is negative (high bit in b1 set) - if ((b1 & 0x80) == 0x80) { - // Make the the whole int negative - ret |= 0xff000000; - } - return ret; - } - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putMediumInt(int value) { - byte b1 = (byte) (value >> 16); - byte b2 = (byte) (value >> 8); - byte b3 = (byte) value; - - if (ByteOrder.BIG_ENDIAN.equals(order())) { - put(b1).put(b2).put(b3); - } else { - put(b3).put(b2).put(b1); - } - - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putMediumInt(int index, int value) { - byte b1 = (byte) (value >> 16); - byte b2 = (byte) (value >> 8); - byte b3 = (byte) value; - - if (ByteOrder.BIG_ENDIAN.equals(order())) { - put(index, b1).put(index + 1, b2).put(index + 2, b3); - } else { - put(index, b3).put(index + 1, b2).put(index + 2, b1); - } - - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public long getUnsignedInt(int index) { - return getInt(index) & 0xffffffffL; - } - - /** - * {@inheritDoc} - */ - @Override - public InputStream asInputStream() { - return new InputStream() { - @Override - public int available() { - return AbstractIoBuffer.this.remaining(); - } - - @Override - public synchronized void mark(int readlimit) { - AbstractIoBuffer.this.mark(); - } - - @Override - public boolean markSupported() { - return true; - } - - @Override - public int read() { - if (AbstractIoBuffer.this.hasRemaining()) { - return AbstractIoBuffer.this.get() & 0xff; - } else { - return -1; - } - } - - @Override - public int read(byte[] b, int off, int len) { - int remaining = AbstractIoBuffer.this.remaining(); - if (remaining > 0) { - int readBytes = Math.min(remaining, len); - AbstractIoBuffer.this.get(b, off, readBytes); - return readBytes; - } else { - return -1; - } - } - - @Override - public synchronized void reset() { - AbstractIoBuffer.this.reset(); - } - - @Override - public long skip(long n) { - int bytes; - if (n > Integer.MAX_VALUE) { - bytes = AbstractIoBuffer.this.remaining(); - } else { - bytes = Math.min(AbstractIoBuffer.this.remaining(), - (int) n); - } - AbstractIoBuffer.this.skip(bytes); - return bytes; - } - }; - } - - /** - * {@inheritDoc} - */ - @Override - public OutputStream asOutputStream() { - return new OutputStream() { - @Override - public void write(byte[] b, int off, int len) { - AbstractIoBuffer.this.put(b, off, len); - } - - @Override - public void write(int b) { - AbstractIoBuffer.this.put((byte) b); - } - }; - } - - /** - * {@inheritDoc} - */ - @Override - public String getHexDump() { - return this.getHexDump(Integer.MAX_VALUE); - } - - /** - * {@inheritDoc} - */ - @Override - public String getHexDump(int lengthLimit) { - return IoBufferHexDumper.getHexdump(this, lengthLimit); - } - - /** - * {@inheritDoc} - */ - @Override - public String getString(CharsetDecoder decoder) - throws CharacterCodingException { - if (!hasRemaining()) { - return ""; - } - - boolean utf16 = decoder.charset().name().startsWith("UTF-16"); - - int oldPos = position(); - int oldLimit = limit(); - int end = -1; - int newPos; - - if (!utf16) { - end = indexOf((byte) 0x00); - if (end < 0) { - newPos = end = oldLimit; - } else { - newPos = end + 1; - } - } else { - int i = oldPos; - for (;;) { - boolean wasZero = get(i) == 0; - i++; - - if (i >= oldLimit) { - break; - } - - if (get(i) != 0) { - i++; - if (i >= oldLimit) { - break; - } else { - continue; - } - } - - if (wasZero) { - end = i - 1; - break; - } - } - - if (end < 0) { - newPos = end = oldPos + (oldLimit - oldPos & 0xFFFFFFFE); - } else { - if (end + 2 <= oldLimit) { - newPos = end + 2; - } else { - newPos = end; - } - } - } - - if (oldPos == end) { - position(newPos); - return ""; - } - - limit(end); - decoder.reset(); - - int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) - + 1; - CharBuffer out = CharBuffer.allocate(expectedLength); - for (;;) { - CoderResult cr; - if (hasRemaining()) { - cr = decoder.decode(buf(), out, true); - } else { - cr = decoder.flush(out); - } - - if (cr.isUnderflow()) { - break; - } - - if (cr.isOverflow()) { - CharBuffer o = CharBuffer - .allocate(out.capacity() + expectedLength); - out.flip(); - o.put(out); - out = o; - continue; - } - - if (cr.isError()) { - // Revert the buffer back to the previous state. - limit(oldLimit); - position(oldPos); - cr.throwException(); - } - } - - limit(oldLimit); - position(newPos); - return out.flip().toString(); - } - - /** - * {@inheritDoc} - */ - @Override - public String getString(int fieldSize, CharsetDecoder decoder) - throws CharacterCodingException { - checkFieldSize(fieldSize); - - if (fieldSize == 0) { - return ""; - } - - if (!hasRemaining()) { - return ""; - } - - boolean utf16 = decoder.charset().name().startsWith("UTF-16"); - - if (utf16 && (fieldSize & 1) != 0) { - throw new IllegalArgumentException("fieldSize is not even."); - } - - int oldPos = position(); - int oldLimit = limit(); - int end = oldPos + fieldSize; - - if (oldLimit < end) { - throw new BufferUnderflowException(); - } - - int i; - - if (!utf16) { - for (i = oldPos; i < end; i++) { - if (get(i) == 0) { - break; - } - } - - if (i == end) { - limit(end); - } else { - limit(i); - } - } else { - for (i = oldPos; i < end; i += 2) { - if (get(i) == 0 && get(i + 1) == 0) { - break; - } - } - - if (i == end) { - limit(end); - } else { - limit(i); - } - } - - if (!hasRemaining()) { - limit(oldLimit); - position(end); - return ""; - } - decoder.reset(); - - int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) - + 1; - CharBuffer out = CharBuffer.allocate(expectedLength); - for (;;) { - CoderResult cr; - if (hasRemaining()) { - cr = decoder.decode(buf(), out, true); - } else { - cr = decoder.flush(out); - } - - if (cr.isUnderflow()) { - break; - } - - if (cr.isOverflow()) { - CharBuffer o = CharBuffer - .allocate(out.capacity() + expectedLength); - out.flip(); - o.put(out); - out = o; - continue; - } - - if (cr.isError()) { - // Revert the buffer back to the previous state. - limit(oldLimit); - position(oldPos); - cr.throwException(); - } - } - - limit(oldLimit); - position(end); - return out.flip().toString(); - } - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putString(CharSequence val, CharsetEncoder encoder) - throws CharacterCodingException { - if (val.length() == 0) { - return this; - } - - CharBuffer in = CharBuffer.wrap(val); - encoder.reset(); - - int expandedState = 0; - - for (;;) { - CoderResult cr; - if (in.hasRemaining()) { - cr = encoder.encode(in, buf(), true); - } else { - cr = encoder.flush(buf()); - } - - if (cr.isUnderflow()) { - break; - } - if (cr.isOverflow()) { - if (isAutoExpand()) { - switch (expandedState) { - case 0 : - autoExpand((int) Math.ceil(in.remaining() - * encoder.averageBytesPerChar())); - expandedState++; - break; - case 1 : - autoExpand((int) Math.ceil(in.remaining() - * encoder.maxBytesPerChar())); - expandedState++; - break; - default : - throw new RuntimeException("Expanded by " - + (int) Math.ceil(in.remaining() - * encoder.maxBytesPerChar()) - + " but that wasn't enough for '" + val - + "'"); - } - continue; - } - } else { - expandedState = 0; - } - cr.throwException(); - } - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putString(CharSequence val, int fieldSize, - CharsetEncoder encoder) throws CharacterCodingException { - checkFieldSize(fieldSize); - - if (fieldSize == 0) { - return this; - } - - autoExpand(fieldSize); - - boolean utf16 = encoder.charset().name().startsWith("UTF-16"); - - if (utf16 && (fieldSize & 1) != 0) { - throw new IllegalArgumentException("fieldSize is not even."); - } - - int oldLimit = limit(); - int end = position() + fieldSize; - - if (oldLimit < end) { - throw new BufferOverflowException(); - } - - if (val.length() == 0) { - if (!utf16) { - put((byte) 0x00); - } else { - put((byte) 0x00); - put((byte) 0x00); - } - position(end); - return this; - } - - CharBuffer in = CharBuffer.wrap(val); - limit(end); - encoder.reset(); - - for (;;) { - CoderResult cr; - if (in.hasRemaining()) { - cr = encoder.encode(in, buf(), true); - } else { - cr = encoder.flush(buf()); - } - - if (cr.isUnderflow() || cr.isOverflow()) { - break; - } - cr.throwException(); - } - - limit(oldLimit); - - if (position() < end) { - if (!utf16) { - put((byte) 0x00); - } else { - put((byte) 0x00); - put((byte) 0x00); - } - } - - position(end); - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public String getPrefixedString(CharsetDecoder decoder) - throws CharacterCodingException { - return getPrefixedString(2, decoder); - } - - /** - * Reads a string which has a length field before the actual encoded string, - * using the specified decoder and returns it. - * - * @param prefixLength - * the length of the length field (1, 2, or 4) - * @param decoder - * the decoder to use for decoding the string - * @return the prefixed string - * @throws CharacterCodingException - * when decoding fails - * @throws BufferUnderflowException - * when there is not enough data available - */ - @Override - public String getPrefixedString(int prefixLength, CharsetDecoder decoder) - throws CharacterCodingException { - if (!prefixedDataAvailable(prefixLength)) { - throw new BufferUnderflowException(); - } - - int fieldSize = 0; - - switch (prefixLength) { - case 1 : - fieldSize = getUnsigned(); - break; - case 2 : - fieldSize = getUnsignedShort(); - break; - case 4 : - fieldSize = getInt(); - break; - } - - if (fieldSize == 0) { - return ""; - } - - boolean utf16 = decoder.charset().name().startsWith("UTF-16"); - - if (utf16 && (fieldSize & 1) != 0) { - throw new BufferDataException( - "fieldSize is not even for a UTF-16 string."); - } - - int oldLimit = limit(); - int end = position() + fieldSize; - - if (oldLimit < end) { - throw new BufferUnderflowException(); - } - - limit(end); - decoder.reset(); - - int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) - + 1; - CharBuffer out = CharBuffer.allocate(expectedLength); - for (;;) { - CoderResult cr; - if (hasRemaining()) { - cr = decoder.decode(buf(), out, true); - } else { - cr = decoder.flush(out); - } - - if (cr.isUnderflow()) { - break; - } - - if (cr.isOverflow()) { - CharBuffer o = CharBuffer - .allocate(out.capacity() + expectedLength); - out.flip(); - o.put(out); - out = o; - continue; - } - - cr.throwException(); - } - - limit(oldLimit); - position(end); - return out.flip().toString(); - } - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putPrefixedString(CharSequence in, CharsetEncoder encoder) - throws CharacterCodingException { - return putPrefixedString(in, 2, 0, encoder); - } - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putPrefixedString(CharSequence in, int prefixLength, - CharsetEncoder encoder) throws CharacterCodingException { - return putPrefixedString(in, prefixLength, 0, encoder); - } - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putPrefixedString(CharSequence in, int prefixLength, - int padding, CharsetEncoder encoder) - throws CharacterCodingException { - return putPrefixedString(in, prefixLength, padding, (byte) 0, encoder); - } - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putPrefixedString(CharSequence val, int prefixLength, - int padding, byte padValue, CharsetEncoder encoder) - throws CharacterCodingException { - int maxLength; - switch (prefixLength) { - case 1 : - maxLength = 255; - break; - case 2 : - maxLength = 65535; - break; - case 4 : - maxLength = Integer.MAX_VALUE; - break; - default : - throw new IllegalArgumentException( - "prefixLength: " + prefixLength); - } - - if (val.length() > maxLength) { - throw new IllegalArgumentException( - "The specified string is too long."); - } - if (val.length() == 0) { - switch (prefixLength) { - case 1 : - put((byte) 0); - break; - case 2 : - putShort((short) 0); - break; - case 4 : - putInt(0); - break; - } - return this; - } - - int padMask; - switch (padding) { - case 0 : - case 1 : - padMask = 0; - break; - case 2 : - padMask = 1; - break; - case 4 : - padMask = 3; - break; - default : - throw new IllegalArgumentException("padding: " + padding); - } - - CharBuffer in = CharBuffer.wrap(val); - skip(prefixLength); // make a room for the length field - int oldPos = position(); - encoder.reset(); - - int expandedState = 0; - - for (;;) { - CoderResult cr; - if (in.hasRemaining()) { - cr = encoder.encode(in, buf(), true); - } else { - cr = encoder.flush(buf()); - } - - if (position() - oldPos > maxLength) { - throw new IllegalArgumentException( - "The specified string is too long."); - } - - if (cr.isUnderflow()) { - break; - } - if (cr.isOverflow()) { - if (isAutoExpand()) { - switch (expandedState) { - case 0 : - autoExpand((int) Math.ceil(in.remaining() - * encoder.averageBytesPerChar())); - expandedState++; - break; - case 1 : - autoExpand((int) Math.ceil(in.remaining() - * encoder.maxBytesPerChar())); - expandedState++; - break; - default : - throw new RuntimeException("Expanded by " - + (int) Math.ceil(in.remaining() - * encoder.maxBytesPerChar()) - + " but that wasn't enough for '" + val - + "'"); - } - continue; - } - } else { - expandedState = 0; - } - cr.throwException(); - } - - // Write the length field - fill(padValue, padding - (position() - oldPos & padMask)); - int length = position() - oldPos; - switch (prefixLength) { - case 1 : - put(oldPos - 1, (byte) length); - break; - case 2 : - putShort(oldPos - 2, (short) length); - break; - case 4 : - putInt(oldPos - 4, length); - break; - } - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public Object getObject() throws ClassNotFoundException { - return getObject(Thread.currentThread().getContextClassLoader()); - } - - /** - * {@inheritDoc} - */ - @Override - public Object getObject(final ClassLoader classLoader) - throws ClassNotFoundException { - if (!prefixedDataAvailable(4)) { - throw new BufferUnderflowException(); - } - - int length = getInt(); - if (length <= 4) { - throw new BufferDataException( - "Object length should be greater than 4: " + length); - } - - int oldLimit = limit(); - limit(position() + length); - try { - ObjectInputStream in = new ObjectInputStream(asInputStream()) { - @Override - protected ObjectStreamClass readClassDescriptor() - throws IOException, ClassNotFoundException { - int type = read(); - if (type < 0) { - throw new EOFException(); - } - switch (type) { - case 0 : // Primitive types - return super.readClassDescriptor(); - case 1 : // Non-primitive types - String className = readUTF(); - Class clazz = Class.forName(className, true, - classLoader); - return ObjectStreamClass.lookup(clazz); - default : - throw new StreamCorruptedException( - "Unexpected class descriptor type: " - + type); - } - } - - @Override - protected Class resolveClass(ObjectStreamClass desc) - throws IOException, ClassNotFoundException { - String name = desc.getName(); - try { - return Class.forName(name, false, classLoader); - } catch (ClassNotFoundException ex) { - return super.resolveClass(desc); - } - } - }; - return in.readObject(); - } catch (IOException e) { - throw new BufferDataException(e); - } finally { - limit(oldLimit); - } - } - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putObject(Object o) { - int oldPos = position(); - skip(4); // Make a room for the length field. - try { - ObjectOutputStream out = new ObjectOutputStream(asOutputStream()) { - @Override - protected void writeClassDescriptor(ObjectStreamClass desc) - throws IOException { - if (desc.forClass().isPrimitive()) { - write(0); - super.writeClassDescriptor(desc); - } else { - write(1); - writeUTF(desc.getName()); - } - } - }; - out.writeObject(o); - out.flush(); - } catch (IOException e) { - throw new BufferDataException(e); - } - - // Fill the length field - int newPos = position(); - position(oldPos); - putInt(newPos - oldPos - 4); - position(newPos); - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean prefixedDataAvailable(int prefixLength) { - return prefixedDataAvailable(prefixLength, Integer.MAX_VALUE); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean prefixedDataAvailable(int prefixLength, int maxDataLength) { - if (remaining() < prefixLength) { - return false; - } - - int dataLength; - switch (prefixLength) { - case 1 : - dataLength = getUnsigned(position()); - break; - case 2 : - dataLength = getUnsignedShort(position()); - break; - case 4 : - dataLength = getInt(position()); - break; - default : - throw new IllegalArgumentException( - "prefixLength: " + prefixLength); - } - - if (dataLength < 0 || dataLength > maxDataLength) { - throw new BufferDataException("dataLength: " + dataLength); - } - - return remaining() - prefixLength >= dataLength; - } - - /** - * {@inheritDoc} - */ - @Override - public int indexOf(byte b) { - if (hasArray()) { - int arrayOffset = arrayOffset(); - int beginPos = arrayOffset + position(); - int limit = arrayOffset + limit(); - byte[] array = array(); - - for (int i = beginPos; i < limit; i++) { - if (array[i] == b) { - return i - arrayOffset; - } - } - } else { - int beginPos = position(); - int limit = limit(); - - for (int i = beginPos; i < limit; i++) { - if (get(i) == b) { - return i; - } - } - } - - return -1; - } - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer skip(int size) { - autoExpand(size); - return position(position() + size); - } - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer fill(byte value, int size) { - autoExpand(size); - int q = size >>> 3; - int r = size & 7; - - if (q > 0) { - int intValue = value | value << 8 | value << 16 | value << 24; - long longValue = intValue; - longValue <<= 32; - longValue |= intValue; - - for (int i = q; i > 0; i--) { - putLong(longValue); - } - } - - q = r >>> 2; - r = r & 3; - - if (q > 0) { - int intValue = value | value << 8 | value << 16 | value << 24; - putInt(intValue); - } - - q = r >> 1; - r = r & 1; - - if (q > 0) { - short shortValue = (short) (value | value << 8); - putShort(shortValue); - } - - if (r > 0) { - put(value); - } - - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer fillAndReset(byte value, int size) { - autoExpand(size); - int pos = position(); - try { - fill(value, size); - } finally { - position(pos); - } - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer fill(int size) { - autoExpand(size); - int q = size >>> 3; - int r = size & 7; - - for (int i = q; i > 0; i--) { - putLong(0L); - } - - q = r >>> 2; - r = r & 3; - - if (q > 0) { - putInt(0); - } - - q = r >> 1; - r = r & 1; - - if (q > 0) { - putShort((short) 0); - } - - if (r > 0) { - put((byte) 0); - } - - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer fillAndReset(int size) { - autoExpand(size); - int pos = position(); - try { - fill(size); - } finally { - position(pos); - } - - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public > E getEnum(Class enumClass) { - return toEnum(enumClass, getUnsigned()); - } - - /** - * {@inheritDoc} - */ - @Override - public > E getEnum(int index, Class enumClass) { - return toEnum(enumClass, getUnsigned(index)); - } - - /** - * {@inheritDoc} - */ - @Override - public > E getEnumShort(Class enumClass) { - return toEnum(enumClass, getUnsignedShort()); - } - - /** - * {@inheritDoc} - */ - @Override - public > E getEnumShort(int index, Class enumClass) { - return toEnum(enumClass, getUnsignedShort(index)); - } - - /** - * {@inheritDoc} - */ - @Override - public > E getEnumInt(Class enumClass) { - return toEnum(enumClass, getInt()); - } - - /** - * {@inheritDoc} - */ - @Override - public > E getEnumInt(int index, Class enumClass) { - return toEnum(enumClass, getInt(index)); - } - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putEnum(Enum e) { - if (e.ordinal() > BYTE_MASK) { - throw new IllegalArgumentException( - enumConversionErrorMessage(e, "byte")); - } - return put((byte) e.ordinal()); - } - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putEnum(int index, Enum e) { - if (e.ordinal() > BYTE_MASK) { - throw new IllegalArgumentException( - enumConversionErrorMessage(e, "byte")); - } - return put(index, (byte) e.ordinal()); - } - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putEnumShort(Enum e) { - if (e.ordinal() > SHORT_MASK) { - throw new IllegalArgumentException( - enumConversionErrorMessage(e, "short")); - } - return putShort((short) e.ordinal()); - } - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putEnumShort(int index, Enum e) { - if (e.ordinal() > SHORT_MASK) { - throw new IllegalArgumentException( - enumConversionErrorMessage(e, "short")); - } - return putShort(index, (short) e.ordinal()); - } - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putEnumInt(Enum e) { - return putInt(e.ordinal()); - } - - /** - * {@inheritDoc} - */ - @Override - public IoBuffer putEnumInt(int index, Enum e) { - return putInt(index, e.ordinal()); - } - - private E toEnum(Class enumClass, int i) { - E[] enumConstants = enumClass.getEnumConstants(); - if (i > enumConstants.length) { - throw new IndexOutOfBoundsException(String.format( - "%d is too large of an ordinal to convert to the enum %s", - i, enumClass.getName())); - } - return enumConstants[i]; - } - - private String enumConversionErrorMessage(Enum e, String type) { - return String.format("%s.%s has an ordinal value too large for a %s", - e.getClass().getName(), e.name(), type); - } - - /** - * {@inheritDoc} - */ - @Override - public > EnumSet getEnumSet(Class enumClass) { - return toEnumSet(enumClass, get() & BYTE_MASK); - } - - /** - * {@inheritDoc} - */ - @Override - public > EnumSet getEnumSet(int index, - Class enumClass) { - return toEnumSet(enumClass, get(index) & BYTE_MASK); - } - - /** - * {@inheritDoc} - */ - @Override - public > EnumSet getEnumSetShort(Class enumClass) { - return toEnumSet(enumClass, getShort() & SHORT_MASK); - } - - /** - * {@inheritDoc} - */ - @Override - public > EnumSet getEnumSetShort(int index, - Class enumClass) { - return toEnumSet(enumClass, getShort(index) & SHORT_MASK); - } - - /** - * {@inheritDoc} - */ - @Override - public > EnumSet getEnumSetInt(Class enumClass) { - return toEnumSet(enumClass, getInt() & INT_MASK); - } - - /** - * {@inheritDoc} - */ - @Override - public > EnumSet getEnumSetInt(int index, - Class enumClass) { - return toEnumSet(enumClass, getInt(index) & INT_MASK); - } - - /** - * {@inheritDoc} - */ - @Override - public > EnumSet getEnumSetLong(Class enumClass) { - return toEnumSet(enumClass, getLong()); - } - - /** - * {@inheritDoc} - */ - @Override - public > EnumSet getEnumSetLong(int index, - Class enumClass) { - return toEnumSet(enumClass, getLong(index)); - } - - private > EnumSet toEnumSet(Class clazz, - long vector) { - EnumSet set = EnumSet.noneOf(clazz); - long mask = 1; - for (E e : clazz.getEnumConstants()) { - if ((mask & vector) == mask) { - set.add(e); - } - mask <<= 1; - } - return set; - } - - /** - * {@inheritDoc} - */ - @Override - public > IoBuffer putEnumSet(Set set) { - long vector = toLong(set); - if ((vector & ~BYTE_MASK) != 0) { - throw new IllegalArgumentException( - "The enum set is too large to fit in a byte: " + set); - } - return put((byte) vector); - } - - /** - * {@inheritDoc} - */ - @Override - public > IoBuffer putEnumSet(int index, Set set) { - long vector = toLong(set); - if ((vector & ~BYTE_MASK) != 0) { - throw new IllegalArgumentException( - "The enum set is too large to fit in a byte: " + set); - } - return put(index, (byte) vector); - } - - /** - * {@inheritDoc} - */ - @Override - public > IoBuffer putEnumSetShort(Set set) { - long vector = toLong(set); - if ((vector & ~SHORT_MASK) != 0) { - throw new IllegalArgumentException( - "The enum set is too large to fit in a short: " + set); - } - return putShort((short) vector); - } - - /** - * {@inheritDoc} - */ - @Override - public > IoBuffer putEnumSetShort(int index, Set set) { - long vector = toLong(set); - if ((vector & ~SHORT_MASK) != 0) { - throw new IllegalArgumentException( - "The enum set is too large to fit in a short: " + set); - } - return putShort(index, (short) vector); - } - - /** - * {@inheritDoc} - */ - @Override - public > IoBuffer putEnumSetInt(Set set) { - long vector = toLong(set); - if ((vector & ~INT_MASK) != 0) { - throw new IllegalArgumentException( - "The enum set is too large to fit in an int: " + set); - } - return putInt((int) vector); - } - - /** - * {@inheritDoc} - */ - @Override - public > IoBuffer putEnumSetInt(int index, Set set) { - long vector = toLong(set); - if ((vector & ~INT_MASK) != 0) { - throw new IllegalArgumentException( - "The enum set is too large to fit in an int: " + set); - } - return putInt(index, (int) vector); - } - - /** - * {@inheritDoc} - */ - @Override - public > IoBuffer putEnumSetLong(Set set) { - return putLong(toLong(set)); - } - - /** - * {@inheritDoc} - */ - @Override - public > IoBuffer putEnumSetLong(int index, Set set) { - return putLong(index, toLong(set)); - } - - private > long toLong(Set set) { - long vector = 0; - for (E e : set) { - if (e.ordinal() >= Long.SIZE) { - throw new IllegalArgumentException( - "The enum set is too large to fit in a bit vector: " - + set); - } - vector |= 1L << e.ordinal(); - } - return vector; - } - - /** - * This method forwards the call to {@link #expand(int)} only when - * autoExpand property is true. - */ - private IoBuffer autoExpand(int expectedRemaining) { - if (isAutoExpand()) { - expand(expectedRemaining, true); - } - return this; - } - - /** - * This method forwards the call to {@link #expand(int)} only when - * autoExpand property is true. - */ - private IoBuffer autoExpand(int pos, int expectedRemaining) { - if (isAutoExpand()) { - expand(pos, expectedRemaining, true); - } - return this; - } - - private static void checkFieldSize(int fieldSize) { - if (fieldSize < 0) { - throw new IllegalArgumentException( - "fieldSize cannot be negative: " + fieldSize); - } - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF 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 com.google.code.yanf4j.buffer; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamClass; +import java.io.OutputStream; +import java.io.StreamCorruptedException; +import java.nio.BufferOverflowException; +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.CharBuffer; +import java.nio.DoubleBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.nio.LongBuffer; +import java.nio.ShortBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; +import java.util.EnumSet; +import java.util.Set; + +/** + * A base implementation of {@link IoBuffer}. This implementation assumes that + * {@link IoBuffer#buf()} always returns a correct NIO {@link ByteBuffer} instance. Most + * implementations could extend this class and implement their own buffer management mechanism. + * + * @author The Apache MINA Project (dev@mina.apache.org) + * @version $Rev: 748210 $, $Date: 2009-02-26 18:05:40 +0100 (Thu, 26 Feb 2009) $ + * @see IoBufferAllocator + */ +public abstract class AbstractIoBuffer extends IoBuffer { + /** Tells if a buffer has been created from an existing buffer */ + private final boolean derived; + + /** A flag set to true if the buffer can extend automatically */ + private boolean autoExpand; + + /** A flag set to true if the buffer can shrink automatically */ + private boolean autoShrink; + + /** Tells if a buffer can be expanded */ + private boolean recapacityAllowed = true; + + /** The minimum number of bytes the IoBuffer can hold */ + private int minimumCapacity; + + /** A mask for a byte */ + private static final long BYTE_MASK = 0xFFL; + + /** A mask for a short */ + private static final long SHORT_MASK = 0xFFFFL; + + /** A mask for an int */ + private static final long INT_MASK = 0xFFFFFFFFL; + + /** + * We don't have any access to Buffer.markValue(), so we need to track it down, which will cause + * small extra overhead. + */ + private int mark = -1; + + /** + * Creates a new parent buffer. + * + * @param allocator The allocator to use to create new buffers + * @param initialCapacity The initial buffer capacity when created + */ + protected AbstractIoBuffer(IoBufferAllocator allocator, int initialCapacity) { + setAllocator(allocator); + this.recapacityAllowed = true; + this.derived = false; + this.minimumCapacity = initialCapacity; + } + + /** + * Creates a new derived buffer. A derived buffer uses an existing buffer properties - the + * allocator and capacity -. + * + * @param parent The buffer we get the properties from + */ + protected AbstractIoBuffer(AbstractIoBuffer parent) { + setAllocator(parent.getAllocator()); + this.recapacityAllowed = false; + this.derived = true; + this.minimumCapacity = parent.minimumCapacity; + } + + /** + * {@inheritDoc} + */ + @Override + public final boolean isDirect() { + return buf().isDirect(); + } + + /** + * {@inheritDoc} + */ + @Override + public final boolean isReadOnly() { + return buf().isReadOnly(); + } + + /** + * Sets the underlying NIO buffer instance. + * + * @param newBuf The buffer to store within this IoBuffer + */ + protected abstract void buf(ByteBuffer newBuf); + + /** + * {@inheritDoc} + */ + @Override + public final int minimumCapacity() { + return minimumCapacity; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer minimumCapacity(int minimumCapacity) { + if (minimumCapacity < 0) { + throw new IllegalArgumentException("minimumCapacity: " + minimumCapacity); + } + this.minimumCapacity = minimumCapacity; + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final int capacity() { + return buf().capacity(); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer capacity(int newCapacity) { + if (!recapacityAllowed) { + throw new IllegalStateException("Derived buffers and their parent can't be expanded."); + } + + // Allocate a new buffer and transfer all settings to it. + if (newCapacity > capacity()) { + // Expand: + // // Save the state. + int pos = position(); + int limit = limit(); + ByteOrder bo = order(); + + // // Reallocate. + ByteBuffer oldBuf = buf(); + ByteBuffer newBuf = getAllocator().allocateNioBuffer(newCapacity, isDirect()); + oldBuf.clear(); + newBuf.put(oldBuf); + buf(newBuf); + + // // Restore the state. + buf().limit(limit); + if (mark >= 0) { + buf().position(mark); + buf().mark(); + } + buf().position(pos); + buf().order(bo); + } + + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final boolean isAutoExpand() { + return autoExpand && recapacityAllowed; + } + + /** + * {@inheritDoc} + */ + @Override + public final boolean isAutoShrink() { + return autoShrink && recapacityAllowed; + } + + /** + * {@inheritDoc} + */ + @Override + public final boolean isDerived() { + return derived; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer setAutoExpand(boolean autoExpand) { + if (!recapacityAllowed) { + throw new IllegalStateException("Derived buffers and their parent can't be expanded."); + } + this.autoExpand = autoExpand; + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer setAutoShrink(boolean autoShrink) { + if (!recapacityAllowed) { + throw new IllegalStateException("Derived buffers and their parent can't be shrinked."); + } + this.autoShrink = autoShrink; + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer expand(int expectedRemaining) { + return expand(position(), expectedRemaining, false); + } + + private IoBuffer expand(int expectedRemaining, boolean autoExpand) { + return expand(position(), expectedRemaining, autoExpand); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer expand(int pos, int expectedRemaining) { + return expand(pos, expectedRemaining, false); + } + + private IoBuffer expand(int pos, int expectedRemaining, boolean autoExpand) { + if (!recapacityAllowed) { + throw new IllegalStateException("Derived buffers and their parent can't be expanded."); + } + + int end = pos + expectedRemaining; + int newCapacity; + if (autoExpand) { + newCapacity = IoBuffer.normalizeCapacity(end); + } else { + newCapacity = end; + } + if (newCapacity > capacity()) { + // The buffer needs expansion. + capacity(newCapacity); + } + + if (end > limit()) { + // We call limit() directly to prevent StackOverflowError + buf().limit(end); + } + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer shrink() { + + if (!recapacityAllowed) { + throw new IllegalStateException("Derived buffers and their parent can't be expanded."); + } + + int position = position(); + int capacity = capacity(); + int limit = limit(); + if (capacity == limit) { + return this; + } + + int newCapacity = capacity; + int minCapacity = Math.max(minimumCapacity, limit); + for (;;) { + if (newCapacity >>> 1 < minCapacity) { + break; + } + newCapacity >>>= 1; + } + + newCapacity = Math.max(minCapacity, newCapacity); + + if (newCapacity == capacity) { + return this; + } + + // Shrink and compact: + // // Save the state. + ByteOrder bo = order(); + + // // Reallocate. + ByteBuffer oldBuf = buf(); + ByteBuffer newBuf = getAllocator().allocateNioBuffer(newCapacity, isDirect()); + oldBuf.position(0); + oldBuf.limit(limit); + newBuf.put(oldBuf); + buf(newBuf); + + // // Restore the state. + buf().position(position); + buf().limit(limit); + buf().order(bo); + mark = -1; + + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final int position() { + return buf().position(); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer position(int newPosition) { + autoExpand(newPosition, 0); + buf().position(newPosition); + if (mark > newPosition) { + mark = -1; + } + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final int limit() { + return buf().limit(); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer limit(int newLimit) { + autoExpand(newLimit, 0); + buf().limit(newLimit); + if (mark > newLimit) { + mark = -1; + } + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer mark() { + buf().mark(); + mark = position(); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final int markValue() { + return mark; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer reset() { + buf().reset(); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer clear() { + buf().clear(); + mark = -1; + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer sweep() { + clear(); + return fillAndReset(remaining()); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer sweep(byte value) { + clear(); + return fillAndReset(value, remaining()); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer flip() { + buf().flip(); + mark = -1; + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer rewind() { + buf().rewind(); + mark = -1; + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final int remaining() { + return limit() - position(); + } + + /** + * {@inheritDoc} + */ + @Override + public final boolean hasRemaining() { + return limit() > position(); + } + + /** + * {@inheritDoc} + */ + @Override + public final byte get() { + return buf().get(); + } + + /** + * {@inheritDoc} + */ + @Override + public final short getUnsigned() { + return (short) (get() & 0xff); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer put(byte b) { + autoExpand(1); + buf().put(b); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final byte get(int index) { + return buf().get(index); + } + + /** + * {@inheritDoc} + */ + @Override + public final short getUnsigned(int index) { + return (short) (get(index) & 0xff); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer put(int index, byte b) { + autoExpand(index, 1); + buf().put(index, b); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer get(byte[] dst, int offset, int length) { + buf().get(dst, offset, length); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer put(ByteBuffer src) { + autoExpand(src.remaining()); + buf().put(src); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer put(byte[] src, int offset, int length) { + autoExpand(length); + buf().put(src, offset, length); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer compact() { + int remaining = remaining(); + int capacity = capacity(); + + if (capacity == 0) { + return this; + } + + if (isAutoShrink() && remaining <= capacity >>> 2 && capacity > minimumCapacity) { + int newCapacity = capacity; + int minCapacity = Math.max(minimumCapacity, remaining << 1); + for (;;) { + if (newCapacity >>> 1 < minCapacity) { + break; + } + newCapacity >>>= 1; + } + + newCapacity = Math.max(minCapacity, newCapacity); + + if (newCapacity == capacity) { + return this; + } + + // Shrink and compact: + // // Save the state. + ByteOrder bo = order(); + + // // Sanity check. + if (remaining > newCapacity) { + throw new IllegalStateException( + "The amount of the remaining bytes is greater than " + "the new capacity."); + } + + // // Reallocate. + ByteBuffer oldBuf = buf(); + ByteBuffer newBuf = getAllocator().allocateNioBuffer(newCapacity, isDirect()); + newBuf.put(oldBuf); + buf(newBuf); + + // // Restore the state. + buf().order(bo); + } else { + buf().compact(); + } + mark = -1; + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final ByteOrder order() { + return buf().order(); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer order(ByteOrder bo) { + buf().order(bo); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final char getChar() { + return buf().getChar(); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer putChar(char value) { + autoExpand(2); + buf().putChar(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final char getChar(int index) { + return buf().getChar(index); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer putChar(int index, char value) { + autoExpand(index, 2); + buf().putChar(index, value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final CharBuffer asCharBuffer() { + return buf().asCharBuffer(); + } + + /** + * {@inheritDoc} + */ + @Override + public final short getShort() { + return buf().getShort(); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer putShort(short value) { + autoExpand(2); + buf().putShort(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final short getShort(int index) { + return buf().getShort(index); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer putShort(int index, short value) { + autoExpand(index, 2); + buf().putShort(index, value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final ShortBuffer asShortBuffer() { + return buf().asShortBuffer(); + } + + /** + * {@inheritDoc} + */ + @Override + public final int getInt() { + return buf().getInt(); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer putInt(int value) { + autoExpand(4); + buf().putInt(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final int getInt(int index) { + return buf().getInt(index); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer putInt(int index, int value) { + autoExpand(index, 4); + buf().putInt(index, value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final IntBuffer asIntBuffer() { + return buf().asIntBuffer(); + } + + /** + * {@inheritDoc} + */ + @Override + public final long getLong() { + return buf().getLong(); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer putLong(long value) { + autoExpand(8); + buf().putLong(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final long getLong(int index) { + return buf().getLong(index); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer putLong(int index, long value) { + autoExpand(index, 8); + buf().putLong(index, value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final LongBuffer asLongBuffer() { + return buf().asLongBuffer(); + } + + /** + * {@inheritDoc} + */ + @Override + public final float getFloat() { + return buf().getFloat(); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer putFloat(float value) { + autoExpand(4); + buf().putFloat(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final float getFloat(int index) { + return buf().getFloat(index); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer putFloat(int index, float value) { + autoExpand(index, 4); + buf().putFloat(index, value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final FloatBuffer asFloatBuffer() { + return buf().asFloatBuffer(); + } + + /** + * {@inheritDoc} + */ + @Override + public final double getDouble() { + return buf().getDouble(); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer putDouble(double value) { + autoExpand(8); + buf().putDouble(value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final double getDouble(int index) { + return buf().getDouble(index); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer putDouble(int index, double value) { + autoExpand(index, 8); + buf().putDouble(index, value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public final DoubleBuffer asDoubleBuffer() { + return buf().asDoubleBuffer(); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer asReadOnlyBuffer() { + recapacityAllowed = false; + return asReadOnlyBuffer0(); + } + + /** + * Implement this method to return the unexpandable read only version of this buffer. + */ + protected abstract IoBuffer asReadOnlyBuffer0(); + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer duplicate() { + recapacityAllowed = false; + return duplicate0(); + } + + /** + * Implement this method to return the unexpandable duplicate of this buffer. + */ + protected abstract IoBuffer duplicate0(); + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer slice() { + recapacityAllowed = false; + return slice0(); + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer getSlice(int index, int length) { + if (length < 0) { + throw new IllegalArgumentException("length: " + length); + } + + int limit = limit(); + + if (index > limit) { + throw new IllegalArgumentException("index: " + index); + } + + int endIndex = index + length; + + if (capacity() < endIndex) { + throw new IndexOutOfBoundsException( + "index + length (" + endIndex + ") is greater " + "than capacity (" + capacity() + ")."); + } + + clear(); + position(index); + limit(endIndex); + + IoBuffer slice = slice(); + position(index); + limit(limit); + return slice; + } + + /** + * {@inheritDoc} + */ + @Override + public final IoBuffer getSlice(int length) { + if (length < 0) { + throw new IllegalArgumentException("length: " + length); + } + int pos = position(); + int limit = limit(); + int nextPos = pos + length; + if (limit < nextPos) { + throw new IndexOutOfBoundsException( + "position + length (" + nextPos + ") is greater " + "than limit (" + limit + ")."); + } + + limit(pos + length); + IoBuffer slice = slice(); + position(nextPos); + limit(limit); + return slice; + } + + /** + * Implement this method to return the unexpandable slice of this buffer. + */ + protected abstract IoBuffer slice0(); + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + int h = 1; + int p = position(); + for (int i = limit() - 1; i >= p; i--) { + h = 31 * h + get(i); + } + return h; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof IoBuffer)) { + return false; + } + + IoBuffer that = (IoBuffer) o; + if (this.remaining() != that.remaining()) { + return false; + } + + int p = this.position(); + for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--) { + byte v1 = this.get(i); + byte v2 = that.get(j); + if (v1 != v2) { + return false; + } + } + return true; + } + + /** + * {@inheritDoc} + */ + public int compareTo(IoBuffer that) { + int n = this.position() + Math.min(this.remaining(), that.remaining()); + for (int i = this.position(), j = that.position(); i < n; i++, j++) { + byte v1 = this.get(i); + byte v2 = that.get(j); + if (v1 == v2) { + continue; + } + if (v1 < v2) { + return -1; + } + + return +1; + } + return this.remaining() - that.remaining(); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + if (isDirect()) { + buf.append("DirectBuffer"); + } else { + buf.append("HeapBuffer"); + } + buf.append("[pos="); + buf.append(position()); + buf.append(" lim="); + buf.append(limit()); + buf.append(" cap="); + buf.append(capacity()); + buf.append(": "); + buf.append(getHexDump(16)); + buf.append(']'); + return buf.toString(); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer get(byte[] dst) { + return get(dst, 0, dst.length); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer put(IoBuffer src) { + return put(src.buf()); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer put(byte[] src) { + return put(src, 0, src.length); + } + + /** + * {@inheritDoc} + */ + @Override + public int getUnsignedShort() { + return getShort() & 0xffff; + } + + /** + * {@inheritDoc} + */ + @Override + public int getUnsignedShort(int index) { + return getShort(index) & 0xffff; + } + + /** + * {@inheritDoc} + */ + @Override + public long getUnsignedInt() { + return getInt() & 0xffffffffL; + } + + /** + * {@inheritDoc} + */ + @Override + public int getMediumInt() { + byte b1 = get(); + byte b2 = get(); + byte b3 = get(); + if (ByteOrder.BIG_ENDIAN.equals(order())) { + return getMediumInt(b1, b2, b3); + } else { + return getMediumInt(b3, b2, b1); + } + } + + /** + * {@inheritDoc} + */ + @Override + public int getUnsignedMediumInt() { + int b1 = getUnsigned(); + int b2 = getUnsigned(); + int b3 = getUnsigned(); + if (ByteOrder.BIG_ENDIAN.equals(order())) { + return b1 << 16 | b2 << 8 | b3; + } else { + return b3 << 16 | b2 << 8 | b1; + } + } + + /** + * {@inheritDoc} + */ + @Override + public int getMediumInt(int index) { + byte b1 = get(index); + byte b2 = get(index + 1); + byte b3 = get(index + 2); + if (ByteOrder.BIG_ENDIAN.equals(order())) { + return getMediumInt(b1, b2, b3); + } else { + return getMediumInt(b3, b2, b1); + } + } + + /** + * {@inheritDoc} + */ + @Override + public int getUnsignedMediumInt(int index) { + int b1 = getUnsigned(index); + int b2 = getUnsigned(index + 1); + int b3 = getUnsigned(index + 2); + if (ByteOrder.BIG_ENDIAN.equals(order())) { + return b1 << 16 | b2 << 8 | b3; + } else { + return b3 << 16 | b2 << 8 | b1; + } + } + + /** + * {@inheritDoc} + */ + private int getMediumInt(byte b1, byte b2, byte b3) { + int ret = b1 << 16 & 0xff0000 | b2 << 8 & 0xff00 | b3 & 0xff; + // Check to see if the medium int is negative (high bit in b1 set) + if ((b1 & 0x80) == 0x80) { + // Make the the whole int negative + ret |= 0xff000000; + } + return ret; + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putMediumInt(int value) { + byte b1 = (byte) (value >> 16); + byte b2 = (byte) (value >> 8); + byte b3 = (byte) value; + + if (ByteOrder.BIG_ENDIAN.equals(order())) { + put(b1).put(b2).put(b3); + } else { + put(b3).put(b2).put(b1); + } + + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putMediumInt(int index, int value) { + byte b1 = (byte) (value >> 16); + byte b2 = (byte) (value >> 8); + byte b3 = (byte) value; + + if (ByteOrder.BIG_ENDIAN.equals(order())) { + put(index, b1).put(index + 1, b2).put(index + 2, b3); + } else { + put(index, b3).put(index + 1, b2).put(index + 2, b1); + } + + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public long getUnsignedInt(int index) { + return getInt(index) & 0xffffffffL; + } + + /** + * {@inheritDoc} + */ + @Override + public InputStream asInputStream() { + return new InputStream() { + @Override + public int available() { + return AbstractIoBuffer.this.remaining(); + } + + @Override + public synchronized void mark(int readlimit) { + AbstractIoBuffer.this.mark(); + } + + @Override + public boolean markSupported() { + return true; + } + + @Override + public int read() { + if (AbstractIoBuffer.this.hasRemaining()) { + return AbstractIoBuffer.this.get() & 0xff; + } else { + return -1; + } + } + + @Override + public int read(byte[] b, int off, int len) { + int remaining = AbstractIoBuffer.this.remaining(); + if (remaining > 0) { + int readBytes = Math.min(remaining, len); + AbstractIoBuffer.this.get(b, off, readBytes); + return readBytes; + } else { + return -1; + } + } + + @Override + public synchronized void reset() { + AbstractIoBuffer.this.reset(); + } + + @Override + public long skip(long n) { + int bytes; + if (n > Integer.MAX_VALUE) { + bytes = AbstractIoBuffer.this.remaining(); + } else { + bytes = Math.min(AbstractIoBuffer.this.remaining(), (int) n); + } + AbstractIoBuffer.this.skip(bytes); + return bytes; + } + }; + } + + /** + * {@inheritDoc} + */ + @Override + public OutputStream asOutputStream() { + return new OutputStream() { + @Override + public void write(byte[] b, int off, int len) { + AbstractIoBuffer.this.put(b, off, len); + } + + @Override + public void write(int b) { + AbstractIoBuffer.this.put((byte) b); + } + }; + } + + /** + * {@inheritDoc} + */ + @Override + public String getHexDump() { + return this.getHexDump(Integer.MAX_VALUE); + } + + /** + * {@inheritDoc} + */ + @Override + public String getHexDump(int lengthLimit) { + return IoBufferHexDumper.getHexdump(this, lengthLimit); + } + + /** + * {@inheritDoc} + */ + @Override + public String getString(CharsetDecoder decoder) throws CharacterCodingException { + if (!hasRemaining()) { + return ""; + } + + boolean utf16 = decoder.charset().name().startsWith("UTF-16"); + + int oldPos = position(); + int oldLimit = limit(); + int end = -1; + int newPos; + + if (!utf16) { + end = indexOf((byte) 0x00); + if (end < 0) { + newPos = end = oldLimit; + } else { + newPos = end + 1; + } + } else { + int i = oldPos; + for (;;) { + boolean wasZero = get(i) == 0; + i++; + + if (i >= oldLimit) { + break; + } + + if (get(i) != 0) { + i++; + if (i >= oldLimit) { + break; + } else { + continue; + } + } + + if (wasZero) { + end = i - 1; + break; + } + } + + if (end < 0) { + newPos = end = oldPos + (oldLimit - oldPos & 0xFFFFFFFE); + } else { + if (end + 2 <= oldLimit) { + newPos = end + 2; + } else { + newPos = end; + } + } + } + + if (oldPos == end) { + position(newPos); + return ""; + } + + limit(end); + decoder.reset(); + + int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1; + CharBuffer out = CharBuffer.allocate(expectedLength); + for (;;) { + CoderResult cr; + if (hasRemaining()) { + cr = decoder.decode(buf(), out, true); + } else { + cr = decoder.flush(out); + } + + if (cr.isUnderflow()) { + break; + } + + if (cr.isOverflow()) { + CharBuffer o = CharBuffer.allocate(out.capacity() + expectedLength); + out.flip(); + o.put(out); + out = o; + continue; + } + + if (cr.isError()) { + // Revert the buffer back to the previous state. + limit(oldLimit); + position(oldPos); + cr.throwException(); + } + } + + limit(oldLimit); + position(newPos); + return out.flip().toString(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getString(int fieldSize, CharsetDecoder decoder) throws CharacterCodingException { + checkFieldSize(fieldSize); + + if (fieldSize == 0) { + return ""; + } + + if (!hasRemaining()) { + return ""; + } + + boolean utf16 = decoder.charset().name().startsWith("UTF-16"); + + if (utf16 && (fieldSize & 1) != 0) { + throw new IllegalArgumentException("fieldSize is not even."); + } + + int oldPos = position(); + int oldLimit = limit(); + int end = oldPos + fieldSize; + + if (oldLimit < end) { + throw new BufferUnderflowException(); + } + + int i; + + if (!utf16) { + for (i = oldPos; i < end; i++) { + if (get(i) == 0) { + break; + } + } + + if (i == end) { + limit(end); + } else { + limit(i); + } + } else { + for (i = oldPos; i < end; i += 2) { + if (get(i) == 0 && get(i + 1) == 0) { + break; + } + } + + if (i == end) { + limit(end); + } else { + limit(i); + } + } + + if (!hasRemaining()) { + limit(oldLimit); + position(end); + return ""; + } + decoder.reset(); + + int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1; + CharBuffer out = CharBuffer.allocate(expectedLength); + for (;;) { + CoderResult cr; + if (hasRemaining()) { + cr = decoder.decode(buf(), out, true); + } else { + cr = decoder.flush(out); + } + + if (cr.isUnderflow()) { + break; + } + + if (cr.isOverflow()) { + CharBuffer o = CharBuffer.allocate(out.capacity() + expectedLength); + out.flip(); + o.put(out); + out = o; + continue; + } + + if (cr.isError()) { + // Revert the buffer back to the previous state. + limit(oldLimit); + position(oldPos); + cr.throwException(); + } + } + + limit(oldLimit); + position(end); + return out.flip().toString(); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putString(CharSequence val, CharsetEncoder encoder) + throws CharacterCodingException { + if (val.length() == 0) { + return this; + } + + CharBuffer in = CharBuffer.wrap(val); + encoder.reset(); + + int expandedState = 0; + + for (;;) { + CoderResult cr; + if (in.hasRemaining()) { + cr = encoder.encode(in, buf(), true); + } else { + cr = encoder.flush(buf()); + } + + if (cr.isUnderflow()) { + break; + } + if (cr.isOverflow()) { + if (isAutoExpand()) { + switch (expandedState) { + case 0: + autoExpand((int) Math.ceil(in.remaining() * encoder.averageBytesPerChar())); + expandedState++; + break; + case 1: + autoExpand((int) Math.ceil(in.remaining() * encoder.maxBytesPerChar())); + expandedState++; + break; + default: + throw new RuntimeException( + "Expanded by " + (int) Math.ceil(in.remaining() * encoder.maxBytesPerChar()) + + " but that wasn't enough for '" + val + "'"); + } + continue; + } + } else { + expandedState = 0; + } + cr.throwException(); + } + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putString(CharSequence val, int fieldSize, CharsetEncoder encoder) + throws CharacterCodingException { + checkFieldSize(fieldSize); + + if (fieldSize == 0) { + return this; + } + + autoExpand(fieldSize); + + boolean utf16 = encoder.charset().name().startsWith("UTF-16"); + + if (utf16 && (fieldSize & 1) != 0) { + throw new IllegalArgumentException("fieldSize is not even."); + } + + int oldLimit = limit(); + int end = position() + fieldSize; + + if (oldLimit < end) { + throw new BufferOverflowException(); + } + + if (val.length() == 0) { + if (!utf16) { + put((byte) 0x00); + } else { + put((byte) 0x00); + put((byte) 0x00); + } + position(end); + return this; + } + + CharBuffer in = CharBuffer.wrap(val); + limit(end); + encoder.reset(); + + for (;;) { + CoderResult cr; + if (in.hasRemaining()) { + cr = encoder.encode(in, buf(), true); + } else { + cr = encoder.flush(buf()); + } + + if (cr.isUnderflow() || cr.isOverflow()) { + break; + } + cr.throwException(); + } + + limit(oldLimit); + + if (position() < end) { + if (!utf16) { + put((byte) 0x00); + } else { + put((byte) 0x00); + put((byte) 0x00); + } + } + + position(end); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public String getPrefixedString(CharsetDecoder decoder) throws CharacterCodingException { + return getPrefixedString(2, decoder); + } + + /** + * Reads a string which has a length field before the actual encoded string, using the specified + * decoder and returns it. + * + * @param prefixLength the length of the length field (1, 2, or 4) + * @param decoder the decoder to use for decoding the string + * @return the prefixed string + * @throws CharacterCodingException when decoding fails + * @throws BufferUnderflowException when there is not enough data available + */ + @Override + public String getPrefixedString(int prefixLength, CharsetDecoder decoder) + throws CharacterCodingException { + if (!prefixedDataAvailable(prefixLength)) { + throw new BufferUnderflowException(); + } + + int fieldSize = 0; + + switch (prefixLength) { + case 1: + fieldSize = getUnsigned(); + break; + case 2: + fieldSize = getUnsignedShort(); + break; + case 4: + fieldSize = getInt(); + break; + } + + if (fieldSize == 0) { + return ""; + } + + boolean utf16 = decoder.charset().name().startsWith("UTF-16"); + + if (utf16 && (fieldSize & 1) != 0) { + throw new BufferDataException("fieldSize is not even for a UTF-16 string."); + } + + int oldLimit = limit(); + int end = position() + fieldSize; + + if (oldLimit < end) { + throw new BufferUnderflowException(); + } + + limit(end); + decoder.reset(); + + int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1; + CharBuffer out = CharBuffer.allocate(expectedLength); + for (;;) { + CoderResult cr; + if (hasRemaining()) { + cr = decoder.decode(buf(), out, true); + } else { + cr = decoder.flush(out); + } + + if (cr.isUnderflow()) { + break; + } + + if (cr.isOverflow()) { + CharBuffer o = CharBuffer.allocate(out.capacity() + expectedLength); + out.flip(); + o.put(out); + out = o; + continue; + } + + cr.throwException(); + } + + limit(oldLimit); + position(end); + return out.flip().toString(); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putPrefixedString(CharSequence in, CharsetEncoder encoder) + throws CharacterCodingException { + return putPrefixedString(in, 2, 0, encoder); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putPrefixedString(CharSequence in, int prefixLength, CharsetEncoder encoder) + throws CharacterCodingException { + return putPrefixedString(in, prefixLength, 0, encoder); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putPrefixedString(CharSequence in, int prefixLength, int padding, + CharsetEncoder encoder) throws CharacterCodingException { + return putPrefixedString(in, prefixLength, padding, (byte) 0, encoder); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putPrefixedString(CharSequence val, int prefixLength, int padding, byte padValue, + CharsetEncoder encoder) throws CharacterCodingException { + int maxLength; + switch (prefixLength) { + case 1: + maxLength = 255; + break; + case 2: + maxLength = 65535; + break; + case 4: + maxLength = Integer.MAX_VALUE; + break; + default: + throw new IllegalArgumentException("prefixLength: " + prefixLength); + } + + if (val.length() > maxLength) { + throw new IllegalArgumentException("The specified string is too long."); + } + if (val.length() == 0) { + switch (prefixLength) { + case 1: + put((byte) 0); + break; + case 2: + putShort((short) 0); + break; + case 4: + putInt(0); + break; + } + return this; + } + + int padMask; + switch (padding) { + case 0: + case 1: + padMask = 0; + break; + case 2: + padMask = 1; + break; + case 4: + padMask = 3; + break; + default: + throw new IllegalArgumentException("padding: " + padding); + } + + CharBuffer in = CharBuffer.wrap(val); + skip(prefixLength); // make a room for the length field + int oldPos = position(); + encoder.reset(); + + int expandedState = 0; + + for (;;) { + CoderResult cr; + if (in.hasRemaining()) { + cr = encoder.encode(in, buf(), true); + } else { + cr = encoder.flush(buf()); + } + + if (position() - oldPos > maxLength) { + throw new IllegalArgumentException("The specified string is too long."); + } + + if (cr.isUnderflow()) { + break; + } + if (cr.isOverflow()) { + if (isAutoExpand()) { + switch (expandedState) { + case 0: + autoExpand((int) Math.ceil(in.remaining() * encoder.averageBytesPerChar())); + expandedState++; + break; + case 1: + autoExpand((int) Math.ceil(in.remaining() * encoder.maxBytesPerChar())); + expandedState++; + break; + default: + throw new RuntimeException( + "Expanded by " + (int) Math.ceil(in.remaining() * encoder.maxBytesPerChar()) + + " but that wasn't enough for '" + val + "'"); + } + continue; + } + } else { + expandedState = 0; + } + cr.throwException(); + } + + // Write the length field + fill(padValue, padding - (position() - oldPos & padMask)); + int length = position() - oldPos; + switch (prefixLength) { + case 1: + put(oldPos - 1, (byte) length); + break; + case 2: + putShort(oldPos - 2, (short) length); + break; + case 4: + putInt(oldPos - 4, length); + break; + } + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public Object getObject() throws ClassNotFoundException { + return getObject(Thread.currentThread().getContextClassLoader()); + } + + /** + * {@inheritDoc} + */ + @Override + public Object getObject(final ClassLoader classLoader) throws ClassNotFoundException { + if (!prefixedDataAvailable(4)) { + throw new BufferUnderflowException(); + } + + int length = getInt(); + if (length <= 4) { + throw new BufferDataException("Object length should be greater than 4: " + length); + } + + int oldLimit = limit(); + limit(position() + length); + try { + ObjectInputStream in = new ObjectInputStream(asInputStream()) { + @Override + protected ObjectStreamClass readClassDescriptor() + throws IOException, ClassNotFoundException { + int type = read(); + if (type < 0) { + throw new EOFException(); + } + switch (type) { + case 0: // Primitive types + return super.readClassDescriptor(); + case 1: // Non-primitive types + String className = readUTF(); + Class clazz = Class.forName(className, true, classLoader); + return ObjectStreamClass.lookup(clazz); + default: + throw new StreamCorruptedException("Unexpected class descriptor type: " + type); + } + } + + @Override + protected Class resolveClass(ObjectStreamClass desc) + throws IOException, ClassNotFoundException { + String name = desc.getName(); + try { + return Class.forName(name, false, classLoader); + } catch (ClassNotFoundException ex) { + return super.resolveClass(desc); + } + } + }; + return in.readObject(); + } catch (IOException e) { + throw new BufferDataException(e); + } finally { + limit(oldLimit); + } + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putObject(Object o) { + int oldPos = position(); + skip(4); // Make a room for the length field. + try { + ObjectOutputStream out = new ObjectOutputStream(asOutputStream()) { + @Override + protected void writeClassDescriptor(ObjectStreamClass desc) throws IOException { + if (desc.forClass().isPrimitive()) { + write(0); + super.writeClassDescriptor(desc); + } else { + write(1); + writeUTF(desc.getName()); + } + } + }; + out.writeObject(o); + out.flush(); + } catch (IOException e) { + throw new BufferDataException(e); + } + + // Fill the length field + int newPos = position(); + position(oldPos); + putInt(newPos - oldPos - 4); + position(newPos); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean prefixedDataAvailable(int prefixLength) { + return prefixedDataAvailable(prefixLength, Integer.MAX_VALUE); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean prefixedDataAvailable(int prefixLength, int maxDataLength) { + if (remaining() < prefixLength) { + return false; + } + + int dataLength; + switch (prefixLength) { + case 1: + dataLength = getUnsigned(position()); + break; + case 2: + dataLength = getUnsignedShort(position()); + break; + case 4: + dataLength = getInt(position()); + break; + default: + throw new IllegalArgumentException("prefixLength: " + prefixLength); + } + + if (dataLength < 0 || dataLength > maxDataLength) { + throw new BufferDataException("dataLength: " + dataLength); + } + + return remaining() - prefixLength >= dataLength; + } + + /** + * {@inheritDoc} + */ + @Override + public int indexOf(byte b) { + if (hasArray()) { + int arrayOffset = arrayOffset(); + int beginPos = arrayOffset + position(); + int limit = arrayOffset + limit(); + byte[] array = array(); + + for (int i = beginPos; i < limit; i++) { + if (array[i] == b) { + return i - arrayOffset; + } + } + } else { + int beginPos = position(); + int limit = limit(); + + for (int i = beginPos; i < limit; i++) { + if (get(i) == b) { + return i; + } + } + } + + return -1; + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer skip(int size) { + autoExpand(size); + return position(position() + size); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer fill(byte value, int size) { + autoExpand(size); + int q = size >>> 3; + int r = size & 7; + + if (q > 0) { + int intValue = value | value << 8 | value << 16 | value << 24; + long longValue = intValue; + longValue <<= 32; + longValue |= intValue; + + for (int i = q; i > 0; i--) { + putLong(longValue); + } + } + + q = r >>> 2; + r = r & 3; + + if (q > 0) { + int intValue = value | value << 8 | value << 16 | value << 24; + putInt(intValue); + } + + q = r >> 1; + r = r & 1; + + if (q > 0) { + short shortValue = (short) (value | value << 8); + putShort(shortValue); + } + + if (r > 0) { + put(value); + } + + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer fillAndReset(byte value, int size) { + autoExpand(size); + int pos = position(); + try { + fill(value, size); + } finally { + position(pos); + } + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer fill(int size) { + autoExpand(size); + int q = size >>> 3; + int r = size & 7; + + for (int i = q; i > 0; i--) { + putLong(0L); + } + + q = r >>> 2; + r = r & 3; + + if (q > 0) { + putInt(0); + } + + q = r >> 1; + r = r & 1; + + if (q > 0) { + putShort((short) 0); + } + + if (r > 0) { + put((byte) 0); + } + + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer fillAndReset(int size) { + autoExpand(size); + int pos = position(); + try { + fill(size); + } finally { + position(pos); + } + + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public > E getEnum(Class enumClass) { + return toEnum(enumClass, getUnsigned()); + } + + /** + * {@inheritDoc} + */ + @Override + public > E getEnum(int index, Class enumClass) { + return toEnum(enumClass, getUnsigned(index)); + } + + /** + * {@inheritDoc} + */ + @Override + public > E getEnumShort(Class enumClass) { + return toEnum(enumClass, getUnsignedShort()); + } + + /** + * {@inheritDoc} + */ + @Override + public > E getEnumShort(int index, Class enumClass) { + return toEnum(enumClass, getUnsignedShort(index)); + } + + /** + * {@inheritDoc} + */ + @Override + public > E getEnumInt(Class enumClass) { + return toEnum(enumClass, getInt()); + } + + /** + * {@inheritDoc} + */ + @Override + public > E getEnumInt(int index, Class enumClass) { + return toEnum(enumClass, getInt(index)); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putEnum(Enum e) { + if (e.ordinal() > BYTE_MASK) { + throw new IllegalArgumentException(enumConversionErrorMessage(e, "byte")); + } + return put((byte) e.ordinal()); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putEnum(int index, Enum e) { + if (e.ordinal() > BYTE_MASK) { + throw new IllegalArgumentException(enumConversionErrorMessage(e, "byte")); + } + return put(index, (byte) e.ordinal()); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putEnumShort(Enum e) { + if (e.ordinal() > SHORT_MASK) { + throw new IllegalArgumentException(enumConversionErrorMessage(e, "short")); + } + return putShort((short) e.ordinal()); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putEnumShort(int index, Enum e) { + if (e.ordinal() > SHORT_MASK) { + throw new IllegalArgumentException(enumConversionErrorMessage(e, "short")); + } + return putShort(index, (short) e.ordinal()); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putEnumInt(Enum e) { + return putInt(e.ordinal()); + } + + /** + * {@inheritDoc} + */ + @Override + public IoBuffer putEnumInt(int index, Enum e) { + return putInt(index, e.ordinal()); + } + + private E toEnum(Class enumClass, int i) { + E[] enumConstants = enumClass.getEnumConstants(); + if (i > enumConstants.length) { + throw new IndexOutOfBoundsException(String.format( + "%d is too large of an ordinal to convert to the enum %s", i, enumClass.getName())); + } + return enumConstants[i]; + } + + private String enumConversionErrorMessage(Enum e, String type) { + return String.format("%s.%s has an ordinal value too large for a %s", e.getClass().getName(), + e.name(), type); + } + + /** + * {@inheritDoc} + */ + @Override + public > EnumSet getEnumSet(Class enumClass) { + return toEnumSet(enumClass, get() & BYTE_MASK); + } + + /** + * {@inheritDoc} + */ + @Override + public > EnumSet getEnumSet(int index, Class enumClass) { + return toEnumSet(enumClass, get(index) & BYTE_MASK); + } + + /** + * {@inheritDoc} + */ + @Override + public > EnumSet getEnumSetShort(Class enumClass) { + return toEnumSet(enumClass, getShort() & SHORT_MASK); + } + + /** + * {@inheritDoc} + */ + @Override + public > EnumSet getEnumSetShort(int index, Class enumClass) { + return toEnumSet(enumClass, getShort(index) & SHORT_MASK); + } + + /** + * {@inheritDoc} + */ + @Override + public > EnumSet getEnumSetInt(Class enumClass) { + return toEnumSet(enumClass, getInt() & INT_MASK); + } + + /** + * {@inheritDoc} + */ + @Override + public > EnumSet getEnumSetInt(int index, Class enumClass) { + return toEnumSet(enumClass, getInt(index) & INT_MASK); + } + + /** + * {@inheritDoc} + */ + @Override + public > EnumSet getEnumSetLong(Class enumClass) { + return toEnumSet(enumClass, getLong()); + } + + /** + * {@inheritDoc} + */ + @Override + public > EnumSet getEnumSetLong(int index, Class enumClass) { + return toEnumSet(enumClass, getLong(index)); + } + + private > EnumSet toEnumSet(Class clazz, long vector) { + EnumSet set = EnumSet.noneOf(clazz); + long mask = 1; + for (E e : clazz.getEnumConstants()) { + if ((mask & vector) == mask) { + set.add(e); + } + mask <<= 1; + } + return set; + } + + /** + * {@inheritDoc} + */ + @Override + public > IoBuffer putEnumSet(Set set) { + long vector = toLong(set); + if ((vector & ~BYTE_MASK) != 0) { + throw new IllegalArgumentException("The enum set is too large to fit in a byte: " + set); + } + return put((byte) vector); + } + + /** + * {@inheritDoc} + */ + @Override + public > IoBuffer putEnumSet(int index, Set set) { + long vector = toLong(set); + if ((vector & ~BYTE_MASK) != 0) { + throw new IllegalArgumentException("The enum set is too large to fit in a byte: " + set); + } + return put(index, (byte) vector); + } + + /** + * {@inheritDoc} + */ + @Override + public > IoBuffer putEnumSetShort(Set set) { + long vector = toLong(set); + if ((vector & ~SHORT_MASK) != 0) { + throw new IllegalArgumentException("The enum set is too large to fit in a short: " + set); + } + return putShort((short) vector); + } + + /** + * {@inheritDoc} + */ + @Override + public > IoBuffer putEnumSetShort(int index, Set set) { + long vector = toLong(set); + if ((vector & ~SHORT_MASK) != 0) { + throw new IllegalArgumentException("The enum set is too large to fit in a short: " + set); + } + return putShort(index, (short) vector); + } + + /** + * {@inheritDoc} + */ + @Override + public > IoBuffer putEnumSetInt(Set set) { + long vector = toLong(set); + if ((vector & ~INT_MASK) != 0) { + throw new IllegalArgumentException("The enum set is too large to fit in an int: " + set); + } + return putInt((int) vector); + } + + /** + * {@inheritDoc} + */ + @Override + public > IoBuffer putEnumSetInt(int index, Set set) { + long vector = toLong(set); + if ((vector & ~INT_MASK) != 0) { + throw new IllegalArgumentException("The enum set is too large to fit in an int: " + set); + } + return putInt(index, (int) vector); + } + + /** + * {@inheritDoc} + */ + @Override + public > IoBuffer putEnumSetLong(Set set) { + return putLong(toLong(set)); + } + + /** + * {@inheritDoc} + */ + @Override + public > IoBuffer putEnumSetLong(int index, Set set) { + return putLong(index, toLong(set)); + } + + private > long toLong(Set set) { + long vector = 0; + for (E e : set) { + if (e.ordinal() >= Long.SIZE) { + throw new IllegalArgumentException( + "The enum set is too large to fit in a bit vector: " + set); + } + vector |= 1L << e.ordinal(); + } + return vector; + } + + /** + * This method forwards the call to {@link #expand(int)} only when autoExpand property is + * true. + */ + private IoBuffer autoExpand(int expectedRemaining) { + if (isAutoExpand()) { + expand(expectedRemaining, true); + } + return this; + } + + /** + * This method forwards the call to {@link #expand(int)} only when autoExpand property is + * true. + */ + private IoBuffer autoExpand(int pos, int expectedRemaining) { + if (isAutoExpand()) { + expand(pos, expectedRemaining, true); + } + return this; + } + + private static void checkFieldSize(int fieldSize) { + if (fieldSize < 0) { + throw new IllegalArgumentException("fieldSize cannot be negative: " + fieldSize); + } + } +} diff --git a/src/main/java/com/google/code/yanf4j/buffer/BufferDataException.java b/src/main/java/com/google/code/yanf4j/buffer/BufferDataException.java index 3a6048620..d10a5a3a3 100644 --- a/src/main/java/com/google/code/yanf4j/buffer/BufferDataException.java +++ b/src/main/java/com/google/code/yanf4j/buffer/BufferDataException.java @@ -1,50 +1,44 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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 com.google.code.yanf4j.buffer; - -/** - * A {@link RuntimeException} which is thrown when the data the {@link IoBuffer} - * contains is corrupt. - * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev: 671827 $, $Date: 2008-06-26 10:49:48 +0200 (Thu, 26 Jun 2008) - * $ - * - */ -public class BufferDataException extends RuntimeException { - private static final long serialVersionUID = -4138189188602563502L; - - public BufferDataException() { - super(); - } - - public BufferDataException(String message) { - super(message); - } - - public BufferDataException(String message, Throwable cause) { - super(message, cause); - } - - public BufferDataException(Throwable cause) { - super(cause); - } - -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF 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 com.google.code.yanf4j.buffer; + +/** + * A {@link RuntimeException} which is thrown when the data the {@link IoBuffer} contains is + * corrupt. + * + * @author The Apache MINA Project (dev@mina.apache.org) + * @version $Rev: 671827 $, $Date: 2008-06-26 10:49:48 +0200 (Thu, 26 Jun 2008) $ + * + */ +public class BufferDataException extends RuntimeException { + private static final long serialVersionUID = -4138189188602563502L; + + public BufferDataException() { + super(); + } + + public BufferDataException(String message) { + super(message); + } + + public BufferDataException(String message, Throwable cause) { + super(message, cause); + } + + public BufferDataException(Throwable cause) { + super(cause); + } + +} diff --git a/src/main/java/com/google/code/yanf4j/buffer/CachedBufferAllocator.java b/src/main/java/com/google/code/yanf4j/buffer/CachedBufferAllocator.java index 8e1bc8b97..25439bc8a 100644 --- a/src/main/java/com/google/code/yanf4j/buffer/CachedBufferAllocator.java +++ b/src/main/java/com/google/code/yanf4j/buffer/CachedBufferAllocator.java @@ -1,295 +1,271 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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 com.google.code.yanf4j.buffer; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.HashMap; -import java.util.Map; -import java.util.Queue; - -import com.google.code.yanf4j.util.CircularQueue; - -/** - * An {@link IoBufferAllocator} that caches the buffers which are likely to be - * reused during auto-expansion of the buffers. - *

- * In {@link SimpleBufferAllocator}, the underlying {@link ByteBuffer} of the - * {@link IoBuffer} is reallocated on its capacity change, which means the newly - * allocated bigger {@link ByteBuffer} replaces the old small {@link ByteBuffer} - * . Consequently, the old {@link ByteBuffer} is marked for garbage collection. - *

- * It's not a problem in most cases as long as the capacity change doesn't - * happen frequently. However, once it happens too often, it burdens the VM and - * the cost of filling the newly allocated {@link ByteBuffer} with {@code NUL} - * surpass the cost of accessing the cache. In 2 dual-core Opteron Italy 270 - * processors, {@link CachedBufferAllocator} outperformed - * {@link SimpleBufferAllocator} in the following situation: - *

    - *
  • when a 32 bytes buffer is expanded 4 or more times,
  • - *
  • when a 64 bytes buffer is expanded 4 or more times,
  • - *
  • when a 128 bytes buffer is expanded 2 or more times,
  • - *
  • and when a 256 bytes or bigger buffer is expanded 1 or more times.
  • - *
- * Please note the observation above is subject to change in a different - * environment. - *

- * {@link CachedBufferAllocator} uses {@link ThreadLocal} to store the cached - * buffer, allocates buffers whose capacity is power of 2 only and provides - * performance advantage if {@link IoBuffer#free()} is called properly. - * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev: 671827 $, $Date: 2008-06-26 10:49:48 +0200 (Thu, 26 Jun 2008) - * $ - */ -public class CachedBufferAllocator implements IoBufferAllocator { - - private static final int DEFAULT_MAX_POOL_SIZE = 8; - private static final int DEFAULT_MAX_CACHED_BUFFER_SIZE = 1 << 18; // 256KB - - private final int maxPoolSize; - private final int maxCachedBufferSize; - - private final ThreadLocal>> heapBuffers; - private final ThreadLocal>> directBuffers; - - /** - * Creates a new instance with the default parameters ({@literal - * #DEFAULT_MAX_POOL_SIZE} and {@literal #DEFAULT_MAX_CACHED_BUFFER_SIZE}). - */ - public CachedBufferAllocator() { - this(DEFAULT_MAX_POOL_SIZE, DEFAULT_MAX_CACHED_BUFFER_SIZE); - } - - /** - * Creates a new instance. - * - * @param maxPoolSize - * the maximum number of buffers with the same capacity per - * thread. 0 disables this limitation. - * @param maxCachedBufferSize - * the maximum capacity of a cached buffer. A buffer whose - * capacity is bigger than this value is not pooled. 0 - * disables this limitation. - */ - public CachedBufferAllocator(int maxPoolSize, int maxCachedBufferSize) { - if (maxPoolSize < 0) { - throw new IllegalArgumentException("maxPoolSize: " + maxPoolSize); - } - if (maxCachedBufferSize < 0) { - throw new IllegalArgumentException( - "maxCachedBufferSize: " + maxCachedBufferSize); - } - - this.maxPoolSize = maxPoolSize; - this.maxCachedBufferSize = maxCachedBufferSize; - - this.heapBuffers = new ThreadLocal>>() { - @Override - protected Map> initialValue() { - return newPoolMap(); - } - }; - this.directBuffers = new ThreadLocal>>() { - @Override - protected Map> initialValue() { - return newPoolMap(); - } - }; - } - - /** - * Returns the maximum number of buffers with the same capacity per thread. - * 0 means 'no limitation'. - */ - public int getMaxPoolSize() { - return this.maxPoolSize; - } - - /** - * Returns the maximum capacity of a cached buffer. A buffer whose capacity - * is bigger than this value is not pooled. 0 means 'no - * limitation'. - */ - public int getMaxCachedBufferSize() { - return this.maxCachedBufferSize; - } - - private Map> newPoolMap() { - Map> poolMap = new HashMap>(); - int poolSize = this.maxPoolSize == 0 - ? DEFAULT_MAX_POOL_SIZE - : this.maxPoolSize; - for (int i = 0; i < 31; i++) { - poolMap.put(1 << i, new CircularQueue(poolSize)); - } - poolMap.put(0, new CircularQueue(poolSize)); - poolMap.put(Integer.MAX_VALUE, - new CircularQueue(poolSize)); - return poolMap; - } - - public IoBuffer allocate(int requestedCapacity, boolean direct) { - int actualCapacity = IoBuffer.normalizeCapacity(requestedCapacity); - IoBuffer buf; - if (this.maxCachedBufferSize != 0 - && actualCapacity > this.maxCachedBufferSize) { - if (direct) { - buf = wrap(ByteBuffer.allocateDirect(actualCapacity)); - } else { - buf = wrap(ByteBuffer.allocate(actualCapacity)); - } - } else { - Queue pool; - if (direct) { - pool = this.directBuffers.get().get(actualCapacity); - } else { - pool = this.heapBuffers.get().get(actualCapacity); - } - - // Recycle if possible. - buf = pool.poll(); - if (buf != null) { - buf.clear(); - buf.setAutoExpand(false); - buf.order(ByteOrder.BIG_ENDIAN); - } else { - if (direct) { - buf = wrap(ByteBuffer.allocateDirect(actualCapacity)); - } else { - buf = wrap(ByteBuffer.allocate(actualCapacity)); - } - } - } - - buf.limit(requestedCapacity); - return buf; - } - - public ByteBuffer allocateNioBuffer(int capacity, boolean direct) { - return allocate(capacity, direct).buf(); - } - - public IoBuffer wrap(ByteBuffer nioBuffer) { - return new CachedBuffer(nioBuffer); - } - - public void dispose() { - } - - private class CachedBuffer extends AbstractIoBuffer { - private final Thread ownerThread; - private ByteBuffer buf; - - protected CachedBuffer(ByteBuffer buf) { - super(CachedBufferAllocator.this, buf.capacity()); - this.ownerThread = Thread.currentThread(); - this.buf = buf; - buf.order(ByteOrder.BIG_ENDIAN); - } - - protected CachedBuffer(CachedBuffer parent, ByteBuffer buf) { - super(parent); - this.ownerThread = Thread.currentThread(); - this.buf = buf; - } - - @Override - public ByteBuffer buf() { - if (this.buf == null) { - throw new IllegalStateException( - "Buffer has been freed already."); - } - return this.buf; - } - - @Override - protected void buf(ByteBuffer buf) { - ByteBuffer oldBuf = this.buf; - this.buf = buf; - free(oldBuf); - } - - @Override - protected IoBuffer duplicate0() { - return new CachedBuffer(this, buf().duplicate()); - } - - @Override - protected IoBuffer slice0() { - return new CachedBuffer(this, buf().slice()); - } - - @Override - protected IoBuffer asReadOnlyBuffer0() { - return new CachedBuffer(this, buf().asReadOnlyBuffer()); - } - - @Override - public byte[] array() { - return buf().array(); - } - - @Override - public int arrayOffset() { - return buf().arrayOffset(); - } - - @Override - public boolean hasArray() { - return buf().hasArray(); - } - - @Override - public void free() { - free(this.buf); - this.buf = null; - } - - private void free(ByteBuffer oldBuf) { - if (oldBuf == null || oldBuf - .capacity() > CachedBufferAllocator.this.maxCachedBufferSize - || oldBuf.isReadOnly() || isDerived() - || Thread.currentThread() != this.ownerThread) { - return; - } - - // Add to the cache. - Queue pool; - if (oldBuf.isDirect()) { - pool = CachedBufferAllocator.this.directBuffers.get() - .get(oldBuf.capacity()); - } else { - pool = CachedBufferAllocator.this.heapBuffers.get() - .get(oldBuf.capacity()); - } - - if (pool == null) { - return; - } - - // Restrict the size of the pool to prevent OOM. - if (CachedBufferAllocator.this.maxPoolSize == 0 - || pool.size() < CachedBufferAllocator.this.maxPoolSize) { - pool.offer(new CachedBuffer(oldBuf)); - } - } - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF 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 com.google.code.yanf4j.buffer; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.HashMap; +import java.util.Map; +import java.util.Queue; +import com.google.code.yanf4j.util.CircularQueue; + +/** + * An {@link IoBufferAllocator} that caches the buffers which are likely to be reused during + * auto-expansion of the buffers. + *

+ * In {@link SimpleBufferAllocator}, the underlying {@link ByteBuffer} of the {@link IoBuffer} is + * reallocated on its capacity change, which means the newly allocated bigger {@link ByteBuffer} + * replaces the old small {@link ByteBuffer} . Consequently, the old {@link ByteBuffer} is marked + * for garbage collection. + *

+ * It's not a problem in most cases as long as the capacity change doesn't happen frequently. + * However, once it happens too often, it burdens the VM and the cost of filling the newly allocated + * {@link ByteBuffer} with {@code NUL} surpass the cost of accessing the cache. In 2 dual-core + * Opteron Italy 270 processors, {@link CachedBufferAllocator} outperformed + * {@link SimpleBufferAllocator} in the following situation: + *

    + *
  • when a 32 bytes buffer is expanded 4 or more times,
  • + *
  • when a 64 bytes buffer is expanded 4 or more times,
  • + *
  • when a 128 bytes buffer is expanded 2 or more times,
  • + *
  • and when a 256 bytes or bigger buffer is expanded 1 or more times.
  • + *
+ * Please note the observation above is subject to change in a different environment. + *

+ * {@link CachedBufferAllocator} uses {@link ThreadLocal} to store the cached buffer, allocates + * buffers whose capacity is power of 2 only and provides performance advantage if + * {@link IoBuffer#free()} is called properly. + * + * @author The Apache MINA Project (dev@mina.apache.org) + * @version $Rev: 671827 $, $Date: 2008-06-26 10:49:48 +0200 (Thu, 26 Jun 2008) $ + */ +public class CachedBufferAllocator implements IoBufferAllocator { + + private static final int DEFAULT_MAX_POOL_SIZE = 8; + private static final int DEFAULT_MAX_CACHED_BUFFER_SIZE = 1 << 18; // 256KB + + private final int maxPoolSize; + private final int maxCachedBufferSize; + + private final ThreadLocal>> heapBuffers; + private final ThreadLocal>> directBuffers; + + /** + * Creates a new instance with the default parameters ({@literal #DEFAULT_MAX_POOL_SIZE} and + * {@literal #DEFAULT_MAX_CACHED_BUFFER_SIZE}). + */ + public CachedBufferAllocator() { + this(DEFAULT_MAX_POOL_SIZE, DEFAULT_MAX_CACHED_BUFFER_SIZE); + } + + /** + * Creates a new instance. + * + * @param maxPoolSize the maximum number of buffers with the same capacity per thread. 0 + * disables this limitation. + * @param maxCachedBufferSize the maximum capacity of a cached buffer. A buffer whose capacity is + * bigger than this value is not pooled. 0 disables this limitation. + */ + public CachedBufferAllocator(int maxPoolSize, int maxCachedBufferSize) { + if (maxPoolSize < 0) { + throw new IllegalArgumentException("maxPoolSize: " + maxPoolSize); + } + if (maxCachedBufferSize < 0) { + throw new IllegalArgumentException("maxCachedBufferSize: " + maxCachedBufferSize); + } + + this.maxPoolSize = maxPoolSize; + this.maxCachedBufferSize = maxCachedBufferSize; + + this.heapBuffers = new ThreadLocal>>() { + @Override + protected Map> initialValue() { + return newPoolMap(); + } + }; + this.directBuffers = new ThreadLocal>>() { + @Override + protected Map> initialValue() { + return newPoolMap(); + } + }; + } + + /** + * Returns the maximum number of buffers with the same capacity per thread. 0 means 'no + * limitation'. + */ + public int getMaxPoolSize() { + return this.maxPoolSize; + } + + /** + * Returns the maximum capacity of a cached buffer. A buffer whose capacity is bigger than this + * value is not pooled. 0 means 'no limitation'. + */ + public int getMaxCachedBufferSize() { + return this.maxCachedBufferSize; + } + + private Map> newPoolMap() { + Map> poolMap = new HashMap>(); + int poolSize = this.maxPoolSize == 0 ? DEFAULT_MAX_POOL_SIZE : this.maxPoolSize; + for (int i = 0; i < 31; i++) { + poolMap.put(1 << i, new CircularQueue(poolSize)); + } + poolMap.put(0, new CircularQueue(poolSize)); + poolMap.put(Integer.MAX_VALUE, new CircularQueue(poolSize)); + return poolMap; + } + + public IoBuffer allocate(int requestedCapacity, boolean direct) { + int actualCapacity = IoBuffer.normalizeCapacity(requestedCapacity); + IoBuffer buf; + if (this.maxCachedBufferSize != 0 && actualCapacity > this.maxCachedBufferSize) { + if (direct) { + buf = wrap(ByteBuffer.allocateDirect(actualCapacity)); + } else { + buf = wrap(ByteBuffer.allocate(actualCapacity)); + } + } else { + Queue pool; + if (direct) { + pool = this.directBuffers.get().get(actualCapacity); + } else { + pool = this.heapBuffers.get().get(actualCapacity); + } + + // Recycle if possible. + buf = pool.poll(); + if (buf != null) { + buf.clear(); + buf.setAutoExpand(false); + buf.order(ByteOrder.BIG_ENDIAN); + } else { + if (direct) { + buf = wrap(ByteBuffer.allocateDirect(actualCapacity)); + } else { + buf = wrap(ByteBuffer.allocate(actualCapacity)); + } + } + } + + buf.limit(requestedCapacity); + return buf; + } + + public ByteBuffer allocateNioBuffer(int capacity, boolean direct) { + return allocate(capacity, direct).buf(); + } + + public IoBuffer wrap(ByteBuffer nioBuffer) { + return new CachedBuffer(nioBuffer); + } + + public void dispose() {} + + private class CachedBuffer extends AbstractIoBuffer { + private final Thread ownerThread; + private ByteBuffer buf; + + protected CachedBuffer(ByteBuffer buf) { + super(CachedBufferAllocator.this, buf.capacity()); + this.ownerThread = Thread.currentThread(); + this.buf = buf; + buf.order(ByteOrder.BIG_ENDIAN); + } + + protected CachedBuffer(CachedBuffer parent, ByteBuffer buf) { + super(parent); + this.ownerThread = Thread.currentThread(); + this.buf = buf; + } + + @Override + public ByteBuffer buf() { + if (this.buf == null) { + throw new IllegalStateException("Buffer has been freed already."); + } + return this.buf; + } + + @Override + protected void buf(ByteBuffer buf) { + ByteBuffer oldBuf = this.buf; + this.buf = buf; + free(oldBuf); + } + + @Override + protected IoBuffer duplicate0() { + return new CachedBuffer(this, buf().duplicate()); + } + + @Override + protected IoBuffer slice0() { + return new CachedBuffer(this, buf().slice()); + } + + @Override + protected IoBuffer asReadOnlyBuffer0() { + return new CachedBuffer(this, buf().asReadOnlyBuffer()); + } + + @Override + public byte[] array() { + return buf().array(); + } + + @Override + public int arrayOffset() { + return buf().arrayOffset(); + } + + @Override + public boolean hasArray() { + return buf().hasArray(); + } + + @Override + public void free() { + free(this.buf); + this.buf = null; + } + + private void free(ByteBuffer oldBuf) { + if (oldBuf == null || oldBuf.capacity() > CachedBufferAllocator.this.maxCachedBufferSize + || oldBuf.isReadOnly() || isDerived() || Thread.currentThread() != this.ownerThread) { + return; + } + + // Add to the cache. + Queue pool; + if (oldBuf.isDirect()) { + pool = CachedBufferAllocator.this.directBuffers.get().get(oldBuf.capacity()); + } else { + pool = CachedBufferAllocator.this.heapBuffers.get().get(oldBuf.capacity()); + } + + if (pool == null) { + return; + } + + // Restrict the size of the pool to prevent OOM. + if (CachedBufferAllocator.this.maxPoolSize == 0 + || pool.size() < CachedBufferAllocator.this.maxPoolSize) { + pool.offer(new CachedBuffer(oldBuf)); + } + } + } +} diff --git a/src/main/java/com/google/code/yanf4j/buffer/IoBuffer.java b/src/main/java/com/google/code/yanf4j/buffer/IoBuffer.java index 96ddb8861..ce5dd4196 100644 --- a/src/main/java/com/google/code/yanf4j/buffer/IoBuffer.java +++ b/src/main/java/com/google/code/yanf4j/buffer/IoBuffer.java @@ -1,1510 +1,1325 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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 com.google.code.yanf4j.buffer; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.BufferOverflowException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.CharBuffer; -import java.nio.DoubleBuffer; -import java.nio.FloatBuffer; -import java.nio.IntBuffer; -import java.nio.LongBuffer; -import java.nio.ReadOnlyBufferException; -import java.nio.ShortBuffer; -import java.nio.charset.CharacterCodingException; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CharsetEncoder; -import java.util.EnumSet; -import java.util.Set; - -/** - * A byte buffer used by MINA applications. - *

- * This is a replacement for {@link ByteBuffer}. Please refer to - * {@link ByteBuffer} documentation for preliminary usage. MINA does not use NIO - * {@link ByteBuffer} directly for two reasons: - *

    - *
  • It doesn't provide useful getters and putters such as fill, - * get/putString, and get/putAsciiInt() enough.
  • - *
  • It is difficult to write variable-length data due to its fixed - * capacity
  • - *
- *

- * - *

Allocation

- *

- * You can allocate a new heap buffer. - * - *

- * IoBuffer buf = IoBuffer.allocate(1024, false);
- * 
- * - * you can also allocate a new direct buffer: - * - *
- * IoBuffer buf = IoBuffer.allocate(1024, true);
- * 
- * - * or you can set the default buffer type. - * - *
- * // Allocate heap buffer by default.
- * IoBuffer.setUseDirectBuffer(false);
- * // A new heap buffer is returned.
- * IoBuffer buf = IoBuffer.allocate(1024);
- * 
- * - *

- * - *

Wrapping existing NIO buffers and arrays

- *

- * This class provides a few wrap(...) methods that wraps any NIO - * buffers and byte arrays. - * - *

AutoExpand

- *

- * Writing variable-length data using NIO ByteBuffers is not really - * easy, and it is because its size is fixed. {@link IoBuffer} introduces - * autoExpand property. If autoExpand property is true, you - * never get {@link BufferOverflowException} or - * {@link IndexOutOfBoundsException} (except when index is negative). It - * automatically expands its capacity and limit value. For example: - * - *

- * String greeting = messageBundle.getMessage("hello");
- * IoBuffer buf = IoBuffer.allocate(16);
- * // Turn on autoExpand (it is off by default)
- * buf.setAutoExpand(true);
- * buf.putString(greeting, utf8encoder);
- * 
- * - * The underlying {@link ByteBuffer} is reallocated by {@link IoBuffer} behind - * the scene if the encoded data is larger than 16 bytes in the example above. - * Its capacity will double, and its limit will increase to the last position - * the string is written. - *

- * - *

AutoShrink

- *

- * You might also want to decrease the capacity of the buffer when most of the - * allocated memory area is not being used. {@link IoBuffer} provides - * autoShrink property to take care of this issue. If - * autoShrink is turned on, {@link IoBuffer} halves the capacity of the - * buffer when {@link #compact()} is invoked and only 1/4 or less of the current - * capacity is being used. - *

- * You can also {@link #shrink()} method manually to shrink the capacity of the - * buffer. - *

- * The underlying {@link ByteBuffer} is reallocated by {@link IoBuffer} behind - * the scene, and therefore {@link #buf()} will return a different - * {@link ByteBuffer} instance once capacity changes. Please also note - * {@link #compact()} or {@link #shrink()} will not decrease the capacity if the - * new capacity is less than the {@link #minimumCapacity()} of the buffer. - * - *

Derived Buffers

- *

- * Derived buffers are the buffers which were created by {@link #duplicate()}, - * {@link #slice()}, or {@link #asReadOnlyBuffer()}. They are useful especially - * when you broadcast the same messages to multiple {@link IoSession}s. Please - * note that the buffer derived from and its derived buffers are not both - * auto-expandable neither auto-shrinkable. Trying to call - * {@link #setAutoExpand(boolean)} or {@link #setAutoShrink(boolean)} with - * true parameter will raise an {@link IllegalStateException}. - *

- * - *

Changing Buffer Allocation Policy

- *

- * {@link IoBufferAllocator} interface lets you override the default buffer - * management behavior. There are two allocators provided out-of-the-box: - *

    - *
  • {@link SimpleBufferAllocator} (default)
  • - *
  • {@link CachedBufferAllocator}
  • - *
- * You can implement your own allocator and use it by calling - * {@link #setAllocator(IoBufferAllocator)}. - *

- * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev: 748525 $, $Date: 2009-02-27 14:45:31 +0100 (Fri, 27 Feb 2009) - * $ - */ -public abstract class IoBuffer implements Comparable { - /** The allocator used to create new buffers */ - private static IoBufferAllocator allocator = new SimpleBufferAllocator(); - - /** A flag indicating which type of buffer we are using : heap or direct */ - private static boolean useDirectBuffer = false; - - /** - * Returns the allocator used by existing and new buffers - */ - public static IoBufferAllocator getAllocator() { - return allocator; - } - - /** - * Sets the allocator used by existing and new buffers - */ - public static void setAllocator(IoBufferAllocator newAllocator) { - if (newAllocator == null) { - throw new NullPointerException("allocator"); - } - - IoBufferAllocator oldAllocator = allocator; - - allocator = newAllocator; - - if (null != oldAllocator) { - oldAllocator.dispose(); - } - } - - /** - * Returns true if and only if a direct buffer is allocated by - * default when the type of the new buffer is not specified. The default - * value is false. - */ - public static boolean isUseDirectBuffer() { - return useDirectBuffer; - } - - /** - * Sets if a direct buffer should be allocated by default when the type of - * the new buffer is not specified. The default value is false. - */ - public static void setUseDirectBuffer(boolean useDirectBuffer) { - IoBuffer.useDirectBuffer = useDirectBuffer; - } - - /** - * Returns the direct or heap buffer which is capable to store the specified - * amount of bytes. - * - * @param capacity - * the capacity of the buffer - * - * @see #setUseDirectBuffer(boolean) - */ - public static IoBuffer allocate(int capacity) { - return allocate(capacity, useDirectBuffer); - } - - /** - * Returns the buffer which is capable of the specified size. - * - * @param capacity - * the capacity of the buffer - * @param direct - * true to get a direct buffer, false to get a - * heap buffer. - */ - public static IoBuffer allocate(int capacity, boolean direct) { - if (capacity < 0) { - throw new IllegalArgumentException("capacity: " + capacity); - } - - return allocator.allocate(capacity, direct); - } - - /** - * Wraps the specified NIO {@link ByteBuffer} into MINA buffer. - */ - public static IoBuffer wrap(ByteBuffer nioBuffer) { - return allocator.wrap(nioBuffer); - } - - /** - * Wraps the specified byte array into MINA heap buffer. - */ - public static IoBuffer wrap(byte[] byteArray) { - return wrap(ByteBuffer.wrap(byteArray)); - } - - /** - * Wraps the specified byte array into MINA heap buffer. - */ - public static IoBuffer wrap(byte[] byteArray, int offset, int length) { - return wrap(ByteBuffer.wrap(byteArray, offset, length)); - } - - /** - * Normalizes the specified capacity of the buffer to power of 2, which is - * often helpful for optimal memory usage and performance. If it is greater - * than or equal to {@link Integer#MAX_VALUE}, it returns - * {@link Integer#MAX_VALUE}. If it is zero, it returns zero. - */ - protected static int normalizeCapacity(int requestedCapacity) { - switch (requestedCapacity) { - case 0 : - case 1 << 0 : - case 1 << 1 : - case 1 << 2 : - case 1 << 3 : - case 1 << 4 : - case 1 << 5 : - case 1 << 6 : - case 1 << 7 : - case 1 << 8 : - case 1 << 9 : - case 1 << 10 : - case 1 << 11 : - case 1 << 12 : - case 1 << 13 : - case 1 << 14 : - case 1 << 15 : - case 1 << 16 : - case 1 << 17 : - case 1 << 18 : - case 1 << 19 : - case 1 << 21 : - case 1 << 22 : - case 1 << 23 : - case 1 << 24 : - case 1 << 25 : - case 1 << 26 : - case 1 << 27 : - case 1 << 28 : - case 1 << 29 : - case 1 << 30 : - case Integer.MAX_VALUE : - return requestedCapacity; - } - - int newCapacity = 1; - while (newCapacity < requestedCapacity) { - newCapacity <<= 1; - if (newCapacity < 0) { - return Integer.MAX_VALUE; - } - } - return newCapacity; - } - - /** - * Creates a new instance. This is an empty constructor. - */ - protected IoBuffer() { - } - - /** - * Declares this buffer and all its derived buffers are not used anymore so - * that it can be reused by some {@link IoBufferAllocator} implementations. - * It is not mandatory to call this method, but you might want to invoke - * this method for maximum performance. - */ - public abstract void free(); - - /** - * Returns the underlying NIO buffer instance. - */ - public abstract ByteBuffer buf(); - - /** - * @see ByteBuffer#isDirect() - */ - public abstract boolean isDirect(); - - /** - * returns true if and only if this buffer is derived from other - * buffer via {@link #duplicate()}, {@link #slice()} or - * {@link #asReadOnlyBuffer()}. - */ - public abstract boolean isDerived(); - - /** - * @see ByteBuffer#isReadOnly() - */ - public abstract boolean isReadOnly(); - - /** - * Returns the minimum capacity of this buffer which is used to determine - * the new capacity of the buffer shrunk by {@link #compact()} and - * {@link #shrink()} operation. The default value is the initial capacity of - * the buffer. - */ - public abstract int minimumCapacity(); - - /** - * Sets the minimum capacity of this buffer which is used to determine the - * new capacity of the buffer shrunk by {@link #compact()} and - * {@link #shrink()} operation. The default value is the initial capacity of - * the buffer. - */ - public abstract IoBuffer minimumCapacity(int minimumCapacity); - - /** - * @see ByteBuffer#capacity() - */ - public abstract int capacity(); - - /** - * Increases the capacity of this buffer. If the new capacity is less than - * or equal to the current capacity, this method returns silently. If the - * new capacity is greater than the current capacity, the buffer is - * reallocated while retaining the position, limit, mark and the content of - * the buffer. - */ - public abstract IoBuffer capacity(int newCapacity); - - /** - * Returns true if and only if autoExpand is turned on. - */ - public abstract boolean isAutoExpand(); - - /** - * Turns on or off autoExpand. - */ - public abstract IoBuffer setAutoExpand(boolean autoExpand); - - /** - * Returns true if and only if autoShrink is turned on. - */ - public abstract boolean isAutoShrink(); - - /** - * Turns on or off autoShrink. - */ - public abstract IoBuffer setAutoShrink(boolean autoShrink); - - /** - * Changes the capacity and limit of this buffer so this buffer get the - * specified expectedRemaining room from the current position. This - * method works even if you didn't set autoExpand to true. - */ - public abstract IoBuffer expand(int expectedRemaining); - - /** - * Changes the capacity and limit of this buffer so this buffer get the - * specified expectedRemaining room from the specified - * position. This method works even if you didn't set - * autoExpand to true. - */ - public abstract IoBuffer expand(int position, int expectedRemaining); - - /** - * Changes the capacity of this buffer so this buffer occupies as less - * memory as possible while retaining the position, limit and the buffer - * content between the position and limit. The capacity of the buffer never - * becomes less than {@link #minimumCapacity()}. The mark is discarded once - * the capacity changes. - */ - public abstract IoBuffer shrink(); - - /** - * @see java.nio.Buffer#position() - */ - public abstract int position(); - - /** - * @see java.nio.Buffer#position(int) - */ - public abstract IoBuffer position(int newPosition); - - /** - * @see java.nio.Buffer#limit() - */ - public abstract int limit(); - - /** - * @see java.nio.Buffer#limit(int) - */ - public abstract IoBuffer limit(int newLimit); - - /** - * @see java.nio.Buffer#mark() - */ - public abstract IoBuffer mark(); - - /** - * Returns the position of the current mark. This method returns -1 - * if no mark is set. - */ - public abstract int markValue(); - - /** - * @see java.nio.Buffer#reset() - */ - public abstract IoBuffer reset(); - - /** - * @see java.nio.Buffer#clear() - */ - public abstract IoBuffer clear(); - - /** - * Clears this buffer and fills its content with NUL. The position - * is set to zero, the limit is set to the capacity, and the mark is - * discarded. - */ - public abstract IoBuffer sweep(); - - /** - * double Clears this buffer and fills its content with value. The - * position is set to zero, the limit is set to the capacity, and the mark - * is discarded. - */ - public abstract IoBuffer sweep(byte value); - - /** - * @see java.nio.Buffer#flip() - */ - public abstract IoBuffer flip(); - - /** - * @see java.nio.Buffer#rewind() - */ - public abstract IoBuffer rewind(); - - /** - * @see java.nio.Buffer#remaining() - */ - public abstract int remaining(); - - /** - * @see java.nio.Buffer#hasRemaining() - */ - public abstract boolean hasRemaining(); - - /** - * @see ByteBuffer#duplicate() - */ - public abstract IoBuffer duplicate(); - - /** - * @see ByteBuffer#slice() - */ - public abstract IoBuffer slice(); - - /** - * @see ByteBuffer#asReadOnlyBuffer() - */ - public abstract IoBuffer asReadOnlyBuffer(); - - /** - * @see ByteBuffer#hasArray() - */ - public abstract boolean hasArray(); - - /** - * @see ByteBuffer#array() - */ - public abstract byte[] array(); - - /** - * @see ByteBuffer#arrayOffset() - */ - public abstract int arrayOffset(); - - /** - * @see ByteBuffer#get() - */ - public abstract byte get(); - - /** - * Reads one unsigned byte as a short integer. - */ - public abstract short getUnsigned(); - - /** - * @see ByteBuffer#put(byte) - */ - public abstract IoBuffer put(byte b); - - /** - * @see ByteBuffer#get(int) - */ - public abstract byte get(int index); - - /** - * Reads one byte as an unsigned short integer. - */ - public abstract short getUnsigned(int index); - - /** - * @see ByteBuffer#put(int, byte) - */ - public abstract IoBuffer put(int index, byte b); - - /** - * @see ByteBuffer#get(byte[], int, int) - */ - public abstract IoBuffer get(byte[] dst, int offset, int length); - - /** - * @see ByteBuffer#get(byte[]) - */ - public abstract IoBuffer get(byte[] dst); - - /** - * TODO document me. - */ - public abstract IoBuffer getSlice(int index, int length); - - /** - * TODO document me. - */ - public abstract IoBuffer getSlice(int length); - - /** - * Writes the content of the specified src into this buffer. - */ - public abstract IoBuffer put(ByteBuffer src); - - /** - * Writes the content of the specified src into this buffer. - */ - public abstract IoBuffer put(IoBuffer src); - - /** - * @see ByteBuffer#put(byte[], int, int) - */ - public abstract IoBuffer put(byte[] src, int offset, int length); - - /** - * @see ByteBuffer#put(byte[]) - */ - public abstract IoBuffer put(byte[] src); - - /** - * @see ByteBuffer#compact() - */ - public abstract IoBuffer compact(); - - /** - * @see ByteBuffer#order() - */ - public abstract ByteOrder order(); - - /** - * @see ByteBuffer#order(ByteOrder) - */ - public abstract IoBuffer order(ByteOrder bo); - - /** - * @see ByteBuffer#getChar() - */ - public abstract char getChar(); - - /** - * @see ByteBuffer#putChar(char) - */ - public abstract IoBuffer putChar(char value); - - /** - * @see ByteBuffer#getChar(int) - */ - public abstract char getChar(int index); - - /** - * @see ByteBuffer#putChar(int, char) - */ - public abstract IoBuffer putChar(int index, char value); - - /** - * @see ByteBuffer#asCharBuffer() - */ - public abstract CharBuffer asCharBuffer(); - - /** - * @see ByteBuffer#getShort() - */ - public abstract short getShort(); - - /** - * Reads two bytes unsigned integer. - */ - public abstract int getUnsignedShort(); - - /** - * @see ByteBuffer#putShort(short) - */ - public abstract IoBuffer putShort(short value); - - /** - * @see ByteBuffer#getShort() - */ - public abstract short getShort(int index); - - /** - * Reads two bytes unsigned integer. - */ - public abstract int getUnsignedShort(int index); - - /** - * @see ByteBuffer#putShort(int, short) - */ - public abstract IoBuffer putShort(int index, short value); - - /** - * @see ByteBuffer#asShortBuffer() - */ - public abstract ShortBuffer asShortBuffer(); - - /** - * @see ByteBuffer#getInt() - */ - public abstract int getInt(); - - /** - * Reads four bytes unsigned integer. - */ - public abstract long getUnsignedInt(); - - /** - * Relative get method for reading a medium int value. - * - *

- * Reads the next three bytes at this buffer's current position, composing - * them into an int value according to the current byte order, and then - * increments the position by three. - *

- * - * @return The medium int value at the buffer's current position - */ - public abstract int getMediumInt(); - - /** - * Relative get method for reading an unsigned medium int value. - * - *

- * Reads the next three bytes at this buffer's current position, composing - * them into an int value according to the current byte order, and then - * increments the position by three. - *

- * - * @return The unsigned medium int value at the buffer's current position - */ - public abstract int getUnsignedMediumInt(); - - /** - * Absolute get method for reading a medium int value. - * - *

- * Reads the next three bytes at this buffer's current position, composing - * them into an int value according to the current byte order. - *

- * - * @param index - * The index from which the medium int will be read - * @return The medium int value at the given index - * - * @throws IndexOutOfBoundsException - * If index is negative or not smaller than the - * buffer's limit - */ - public abstract int getMediumInt(int index); - - /** - * Absolute get method for reading an unsigned medium int value. - * - *

- * Reads the next three bytes at this buffer's current position, composing - * them into an int value according to the current byte order. - *

- * - * @param index - * The index from which the unsigned medium int will be read - * @return The unsigned medium int value at the given index - * - * @throws IndexOutOfBoundsException - * If index is negative or not smaller than the - * buffer's limit - */ - public abstract int getUnsignedMediumInt(int index); - - /** - * Relative put method for writing a medium int value. - * - *

- * Writes three bytes containing the given int value, in the current byte - * order, into this buffer at the current position, and then increments the - * position by three. - *

- * - * @param value - * The medium int value to be written - * - * @return This buffer - * - * @throws BufferOverflowException - * If there are fewer than three bytes remaining in this buffer - * - * @throws ReadOnlyBufferException - * If this buffer is read-only - */ - public abstract IoBuffer putMediumInt(int value); - - /** - * Absolute put method for writing a medium int value. - * - *

- * Writes three bytes containing the given int value, in the current byte - * order, into this buffer at the given index. - *

- * - * @param index - * The index at which the bytes will be written - * - * @param value - * The medium int value to be written - * - * @return This buffer - * - * @throws IndexOutOfBoundsException - * If index is negative or not smaller than the - * buffer's limit, minus three - * - * @throws ReadOnlyBufferException - * If this buffer is read-only - */ - public abstract IoBuffer putMediumInt(int index, int value); - - /** - * @see ByteBuffer#putInt(int) - */ - public abstract IoBuffer putInt(int value); - - /** - * @see ByteBuffer#getInt(int) - */ - public abstract int getInt(int index); - - /** - * Reads four bytes unsigned integer. - */ - public abstract long getUnsignedInt(int index); - - /** - * @see ByteBuffer#putInt(int, int) - */ - public abstract IoBuffer putInt(int index, int value); - - /** - * @see ByteBuffer#asIntBuffer() - */ - public abstract IntBuffer asIntBuffer(); - - /** - * @see ByteBuffer#getLong() - */ - public abstract long getLong(); - - /** - * @see ByteBuffer#putLong(int, long) - */ - public abstract IoBuffer putLong(long value); - - /** - * @see ByteBuffer#getLong(int) - */ - public abstract long getLong(int index); - - /** - * @see ByteBuffer#putLong(int, long) - */ - public abstract IoBuffer putLong(int index, long value); - - /** - * @see ByteBuffer#asLongBuffer() - */ - public abstract LongBuffer asLongBuffer(); - - /** - * @see ByteBuffer#getFloat() - */ - public abstract float getFloat(); - - /** - * @see ByteBuffer#putFloat(float) - */ - public abstract IoBuffer putFloat(float value); - - /** - * @see ByteBuffer#getFloat(int) - */ - public abstract float getFloat(int index); - - /** - * @see ByteBuffer#putFloat(int, float) - */ - public abstract IoBuffer putFloat(int index, float value); - - /** - * @see ByteBuffer#asFloatBuffer() - */ - public abstract FloatBuffer asFloatBuffer(); - - /** - * @see ByteBuffer#getDouble() - */ - public abstract double getDouble(); - - /** - * @see ByteBuffer#putDouble(double) - */ - public abstract IoBuffer putDouble(double value); - - /** - * @see ByteBuffer#getDouble(int) - */ - public abstract double getDouble(int index); - - /** - * @see ByteBuffer#putDouble(int, double) - */ - public abstract IoBuffer putDouble(int index, double value); - - /** - * @see ByteBuffer#asDoubleBuffer() - */ - public abstract DoubleBuffer asDoubleBuffer(); - - /** - * Returns an {@link InputStream} that reads the data from this buffer. - * {@link InputStream#read()} returns -1 if the buffer position - * reaches to the limit. - */ - public abstract InputStream asInputStream(); - - /** - * Returns an {@link OutputStream} that appends the data into this buffer. - * Please note that the {@link OutputStream#write(int)} will throw a - * {@link BufferOverflowException} instead of an {@link IOException} in case - * of buffer overflow. Please set autoExpand property by calling - * {@link #setAutoExpand(boolean)} to prevent the unexpected runtime - * exception. - */ - public abstract OutputStream asOutputStream(); - - /** - * Returns hexdump of this buffer. The data and pointer are not changed as a - * result of this method call. - * - * @return hexidecimal representation of this buffer - */ - public abstract String getHexDump(); - - /** - * Return hexdump of this buffer with limited length. - * - * @param lengthLimit - * The maximum number of bytes to dump from the current buffer - * position. - * @return hexidecimal representation of this buffer - */ - public abstract String getHexDump(int lengthLimit); - - // ////////////////////////////// - // String getters and putters // - // ////////////////////////////// - - /** - * Reads a NUL-terminated string from this buffer using the - * specified decoder and returns it. This method reads until - * the limit of this buffer if no NUL is found. - */ - public abstract String getString(CharsetDecoder decoder) - throws CharacterCodingException; - - /** - * Reads a NUL-terminated string from this buffer using the - * specified decoder and returns it. - * - * @param fieldSize - * the maximum number of bytes to read - */ - public abstract String getString(int fieldSize, CharsetDecoder decoder) - throws CharacterCodingException; - - /** - * Writes the content of in into this buffer using the - * specified encoder. This method doesn't terminate string with - * NUL. You have to do it by yourself. - * - * @throws BufferOverflowException - * if the specified string doesn't fit - */ - public abstract IoBuffer putString(CharSequence val, CharsetEncoder encoder) - throws CharacterCodingException; - - /** - * Writes the content of in into this buffer as a - * NUL-terminated string using the specified - * encoder. - *

- * If the charset name of the encoder is UTF-16, you cannot specify odd - * fieldSize, and this method will append two NULs - * as a terminator. - *

- * Please note that this method doesn't terminate with NUL if - * the input string is longer than fieldSize. - * - * @param fieldSize - * the maximum number of bytes to write - */ - public abstract IoBuffer putString(CharSequence val, int fieldSize, - CharsetEncoder encoder) throws CharacterCodingException; - - /** - * Reads a string which has a 16-bit length field before the actual encoded - * string, using the specified decoder and returns it. This - * method is a shortcut for getPrefixedString(2, decoder). - */ - public abstract String getPrefixedString(CharsetDecoder decoder) - throws CharacterCodingException; - - /** - * Reads a string which has a length field before the actual encoded string, - * using the specified decoder and returns it. - * - * @param prefixLength - * the length of the length field (1, 2, or 4) - */ - public abstract String getPrefixedString(int prefixLength, - CharsetDecoder decoder) throws CharacterCodingException; - - /** - * Writes the content of in into this buffer as a string which - * has a 16-bit length field before the actual encoded string, using the - * specified encoder. This method is a shortcut for - * putPrefixedString(in, 2, 0, encoder). - * - * @throws BufferOverflowException - * if the specified string doesn't fit - */ - public abstract IoBuffer putPrefixedString(CharSequence in, - CharsetEncoder encoder) throws CharacterCodingException; - - /** - * Writes the content of in into this buffer as a string which - * has a 16-bit length field before the actual encoded string, using the - * specified encoder. This method is a shortcut for - * putPrefixedString(in, prefixLength, 0, encoder). - * - * @param prefixLength - * the length of the length field (1, 2, or 4) - * - * @throws BufferOverflowException - * if the specified string doesn't fit - */ - public abstract IoBuffer putPrefixedString(CharSequence in, - int prefixLength, CharsetEncoder encoder) - throws CharacterCodingException; - - /** - * Writes the content of in into this buffer as a string which - * has a 16-bit length field before the actual encoded string, using the - * specified encoder. This method is a shortcut for - * putPrefixedString(in, prefixLength, padding, ( byte ) 0, encoder) - * . - * - * @param prefixLength - * the length of the length field (1, 2, or 4) - * @param padding - * the number of padded NULs (1 (or 0), 2, or 4) - * - * @throws BufferOverflowException - * if the specified string doesn't fit - */ - public abstract IoBuffer putPrefixedString(CharSequence in, - int prefixLength, int padding, CharsetEncoder encoder) - throws CharacterCodingException; - - /** - * Writes the content of in into this buffer as a string which - * has a 16-bit length field before the actual encoded string, using the - * specified encoder. - * - * @param prefixLength - * the length of the length field (1, 2, or 4) - * @param padding - * the number of padded bytes (1 (or 0), 2, or 4) - * @param padValue - * the value of padded bytes - * - * @throws BufferOverflowException - * if the specified string doesn't fit - */ - public abstract IoBuffer putPrefixedString(CharSequence val, - int prefixLength, int padding, byte padValue, - CharsetEncoder encoder) throws CharacterCodingException; - - /** - * Reads a Java object from the buffer using the context {@link ClassLoader} - * of the current thread. - */ - public abstract Object getObject() throws ClassNotFoundException; - - /** - * Reads a Java object from the buffer using the specified - * classLoader. - */ - public abstract Object getObject(final ClassLoader classLoader) - throws ClassNotFoundException; - - /** - * Writes the specified Java object to the buffer. - */ - public abstract IoBuffer putObject(Object o); - - /** - * Returns true if this buffer contains a data which has a data - * length as a prefix and the buffer has remaining data as enough as - * specified in the data length field. This method is identical with - * prefixedDataAvailable( prefixLength, Integer.MAX_VALUE ). Please - * not that using this method can allow DoS (Denial of Service) attack in - * case the remote peer sends too big data length value. It is recommended - * to use {@link #prefixedDataAvailable(int, int)} instead. - * - * @param prefixLength - * the length of the prefix field (1, 2, or 4) - * - * @throws IllegalArgumentException - * if prefixLength is wrong - * @throws BufferDataException - * if data length is negative - */ - public abstract boolean prefixedDataAvailable(int prefixLength); - - /** - * Returns true if this buffer contains a data which has a data - * length as a prefix and the buffer has remaining data as enough as - * specified in the data length field. - * - * @param prefixLength - * the length of the prefix field (1, 2, or 4) - * @param maxDataLength - * the allowed maximum of the read data length - * - * @throws IllegalArgumentException - * if prefixLength is wrong - * @throws BufferDataException - * if data length is negative or greater then - * maxDataLength - */ - public abstract boolean prefixedDataAvailable(int prefixLength, - int maxDataLength); - - // /////////////////// - // IndexOf methods // - // /////////////////// - - /** - * Returns the first occurence position of the specified byte from the - * current position to the current limit. - * - * @return -1 if the specified byte is not found - */ - public abstract int indexOf(byte b); - - // //////////////////////// - // Skip or fill methods // - // //////////////////////// - - /** - * Forwards the position of this buffer as the specified size - * bytes. - */ - public abstract IoBuffer skip(int size); - - /** - * Fills this buffer with the specified value. This method moves buffer - * position forward. - */ - public abstract IoBuffer fill(byte value, int size); - - /** - * Fills this buffer with the specified value. This method does not change - * buffer position. - */ - public abstract IoBuffer fillAndReset(byte value, int size); - - /** - * Fills this buffer with NUL (0x00). This method moves buffer - * position forward. - */ - public abstract IoBuffer fill(int size); - - /** - * Fills this buffer with NUL (0x00). This method does not - * change buffer position. - */ - public abstract IoBuffer fillAndReset(int size); - - // //////////////////////// - // Enum methods // - // //////////////////////// - - /** - * Reads a byte from the buffer and returns the correlating enum constant - * defined by the specified enum type. - * - * @param - * The enum type to return - * @param enumClass - * The enum's class object - */ - public abstract > E getEnum(Class enumClass); - - /** - * Reads a byte from the buffer and returns the correlating enum constant - * defined by the specified enum type. - * - * @param - * The enum type to return - * @param index - * the index from which the byte will be read - * @param enumClass - * The enum's class object - */ - public abstract > E getEnum(int index, - Class enumClass); - - /** - * Reads a short from the buffer and returns the correlating enum constant - * defined by the specified enum type. - * - * @param - * The enum type to return - * @param enumClass - * The enum's class object - */ - public abstract > E getEnumShort(Class enumClass); - - /** - * Reads a short from the buffer and returns the correlating enum constant - * defined by the specified enum type. - * - * @param - * The enum type to return - * @param index - * the index from which the bytes will be read - * @param enumClass - * The enum's class object - */ - public abstract > E getEnumShort(int index, - Class enumClass); - - /** - * Reads an int from the buffer and returns the correlating enum constant - * defined by the specified enum type. - * - * @param - * The enum type to return - * @param enumClass - * The enum's class object - */ - public abstract > E getEnumInt(Class enumClass); - - /** - * Reads an int from the buffer and returns the correlating enum constant - * defined by the specified enum type. - * - * @param - * The enum type to return - * @param index - * the index from which the bytes will be read - * @param enumClass - * The enum's class object - */ - public abstract > E getEnumInt(int index, - Class enumClass); - - /** - * Writes an enum's ordinal value to the buffer as a byte. - * - * @param e - * The enum to write to the buffer - */ - public abstract IoBuffer putEnum(Enum e); - - /** - * Writes an enum's ordinal value to the buffer as a byte. - * - * @param index - * The index at which the byte will be written - * @param e - * The enum to write to the buffer - */ - public abstract IoBuffer putEnum(int index, Enum e); - - /** - * Writes an enum's ordinal value to the buffer as a short. - * - * @param e - * The enum to write to the buffer - */ - public abstract IoBuffer putEnumShort(Enum e); - - /** - * Writes an enum's ordinal value to the buffer as a short. - * - * @param index - * The index at which the bytes will be written - * @param e - * The enum to write to the buffer - */ - public abstract IoBuffer putEnumShort(int index, Enum e); - - /** - * Writes an enum's ordinal value to the buffer as an integer. - * - * @param e - * The enum to write to the buffer - */ - public abstract IoBuffer putEnumInt(Enum e); - - /** - * Writes an enum's ordinal value to the buffer as an integer. - * - * @param index - * The index at which the bytes will be written - * @param e - * The enum to write to the buffer - */ - public abstract IoBuffer putEnumInt(int index, Enum e); - - // //////////////////////// - // EnumSet methods // - // //////////////////////// - - /** - * Reads a byte sized bit vector and converts it to an {@link EnumSet}. - * - *

- * Each bit is mapped to a value in the specified enum. The least - * significant bit maps to the first entry in the specified enum and each - * subsequent bit maps to each subsequent bit as mapped to the subsequent - * enum value. - *

- * - * @param - * the enum type - * @param enumClass - * the enum class used to create the EnumSet - * @return the EnumSet representation of the bit vector - */ - public abstract > EnumSet getEnumSet( - Class enumClass); - - /** - * Reads a byte sized bit vector and converts it to an {@link EnumSet}. - * - * @see #getEnumSet(Class) - * @param - * the enum type - * @param index - * the index from which the byte will be read - * @param enumClass - * the enum class used to create the EnumSet - * @return the EnumSet representation of the bit vector - */ - public abstract > EnumSet getEnumSet(int index, - Class enumClass); - - /** - * Reads a short sized bit vector and converts it to an {@link EnumSet}. - * - * @see #getEnumSet(Class) - * @param - * the enum type - * @param enumClass - * the enum class used to create the EnumSet - * @return the EnumSet representation of the bit vector - */ - public abstract > EnumSet getEnumSetShort( - Class enumClass); - - /** - * Reads a short sized bit vector and converts it to an {@link EnumSet}. - * - * @see #getEnumSet(Class) - * @param - * the enum type - * @param index - * the index from which the bytes will be read - * @param enumClass - * the enum class used to create the EnumSet - * @return the EnumSet representation of the bit vector - */ - public abstract > EnumSet getEnumSetShort(int index, - Class enumClass); - - /** - * Reads an int sized bit vector and converts it to an {@link EnumSet}. - * - * @see #getEnumSet(Class) - * @param - * the enum type - * @param enumClass - * the enum class used to create the EnumSet - * @return the EnumSet representation of the bit vector - */ - public abstract > EnumSet getEnumSetInt( - Class enumClass); - - /** - * Reads an int sized bit vector and converts it to an {@link EnumSet}. - * - * @see #getEnumSet(Class) - * @param - * the enum type - * @param index - * the index from which the bytes will be read - * @param enumClass - * the enum class used to create the EnumSet - * @return the EnumSet representation of the bit vector - */ - public abstract > EnumSet getEnumSetInt(int index, - Class enumClass); - - /** - * Reads a long sized bit vector and converts it to an {@link EnumSet}. - * - * @see #getEnumSet(Class) - * @param - * the enum type - * @param enumClass - * the enum class used to create the EnumSet - * @return the EnumSet representation of the bit vector - */ - public abstract > EnumSet getEnumSetLong( - Class enumClass); - - /** - * Reads a long sized bit vector and converts it to an {@link EnumSet}. - * - * @see #getEnumSet(Class) - * @param - * the enum type - * @param index - * the index from which the bytes will be read - * @param enumClass - * the enum class used to create the EnumSet - * @return the EnumSet representation of the bit vector - */ - public abstract > EnumSet getEnumSetLong(int index, - Class enumClass); - - /** - * Writes the specified {@link Set} to the buffer as a byte sized bit - * vector. - * - * @param - * the enum type of the Set - * @param set - * the enum set to write to the buffer - */ - public abstract > IoBuffer putEnumSet(Set set); - - /** - * Writes the specified {@link Set} to the buffer as a byte sized bit - * vector. - * - * @param - * the enum type of the Set - * @param index - * the index at which the byte will be written - * @param set - * the enum set to write to the buffer - */ - public abstract > IoBuffer putEnumSet(int index, - Set set); - - /** - * Writes the specified {@link Set} to the buffer as a short sized bit - * vector. - * - * @param - * the enum type of the Set - * @param set - * the enum set to write to the buffer - */ - public abstract > IoBuffer putEnumSetShort(Set set); - - /** - * Writes the specified {@link Set} to the buffer as a short sized bit - * vector. - * - * @param - * the enum type of the Set - * @param index - * the index at which the bytes will be written - * @param set - * the enum set to write to the buffer - */ - public abstract > IoBuffer putEnumSetShort(int index, - Set set); - - /** - * Writes the specified {@link Set} to the buffer as an int sized bit - * vector. - * - * @param - * the enum type of the Set - * @param set - * the enum set to write to the buffer - */ - public abstract > IoBuffer putEnumSetInt(Set set); - - /** - * Writes the specified {@link Set} to the buffer as an int sized bit - * vector. - * - * @param - * the enum type of the Set - * @param index - * the index at which the bytes will be written - * @param set - * the enum set to write to the buffer - */ - public abstract > IoBuffer putEnumSetInt(int index, - Set set); - - /** - * Writes the specified {@link Set} to the buffer as a long sized bit - * vector. - * - * @param - * the enum type of the Set - * @param set - * the enum set to write to the buffer - */ - public abstract > IoBuffer putEnumSetLong(Set set); - - /** - * Writes the specified {@link Set} to the buffer as a long sized bit - * vector. - * - * @param - * the enum type of the Set - * @param index - * the index at which the bytes will be written - * @param set - * the enum set to write to the buffer - */ - public abstract > IoBuffer putEnumSetLong(int index, - Set set); -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF 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 com.google.code.yanf4j.buffer; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.BufferOverflowException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.CharBuffer; +import java.nio.DoubleBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.nio.LongBuffer; +import java.nio.ReadOnlyBufferException; +import java.nio.ShortBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; +import java.util.EnumSet; +import java.util.Set; + +/** + * A byte buffer used by MINA applications. + *

+ * This is a replacement for {@link ByteBuffer}. Please refer to {@link ByteBuffer} documentation + * for preliminary usage. MINA does not use NIO {@link ByteBuffer} directly for two reasons: + *

    + *
  • It doesn't provide useful getters and putters such as fill, + * get/putString, and get/putAsciiInt() enough.
  • + *
  • It is difficult to write variable-length data due to its fixed capacity
  • + *
+ *

+ * + *

Allocation

+ *

+ * You can allocate a new heap buffer. + * + *

+ * IoBuffer buf = IoBuffer.allocate(1024, false);
+ * 
+ * + * you can also allocate a new direct buffer: + * + *
+ * IoBuffer buf = IoBuffer.allocate(1024, true);
+ * 
+ * + * or you can set the default buffer type. + * + *
+ * // Allocate heap buffer by default.
+ * IoBuffer.setUseDirectBuffer(false);
+ * // A new heap buffer is returned.
+ * IoBuffer buf = IoBuffer.allocate(1024);
+ * 
+ * + *

+ * + *

Wrapping existing NIO buffers and arrays

+ *

+ * This class provides a few wrap(...) methods that wraps any NIO buffers and byte arrays. + * + *

AutoExpand

+ *

+ * Writing variable-length data using NIO ByteBuffers is not really easy, and it is because + * its size is fixed. {@link IoBuffer} introduces autoExpand property. If + * autoExpand property is true, you never get {@link BufferOverflowException} or + * {@link IndexOutOfBoundsException} (except when index is negative). It automatically expands its + * capacity and limit value. For example: + * + *

+ * String greeting = messageBundle.getMessage("hello");
+ * IoBuffer buf = IoBuffer.allocate(16);
+ * // Turn on autoExpand (it is off by default)
+ * buf.setAutoExpand(true);
+ * buf.putString(greeting, utf8encoder);
+ * 
+ * + * The underlying {@link ByteBuffer} is reallocated by {@link IoBuffer} behind the scene if the + * encoded data is larger than 16 bytes in the example above. Its capacity will double, and its + * limit will increase to the last position the string is written. + *

+ * + *

AutoShrink

+ *

+ * You might also want to decrease the capacity of the buffer when most of the allocated memory area + * is not being used. {@link IoBuffer} provides autoShrink property to take care of this + * issue. If autoShrink is turned on, {@link IoBuffer} halves the capacity of the buffer + * when {@link #compact()} is invoked and only 1/4 or less of the current capacity is being used. + *

+ * You can also {@link #shrink()} method manually to shrink the capacity of the buffer. + *

+ * The underlying {@link ByteBuffer} is reallocated by {@link IoBuffer} behind the scene, and + * therefore {@link #buf()} will return a different {@link ByteBuffer} instance once capacity + * changes. Please also note {@link #compact()} or {@link #shrink()} will not decrease the capacity + * if the new capacity is less than the {@link #minimumCapacity()} of the buffer. + * + *

Derived Buffers

+ *

+ * Derived buffers are the buffers which were created by {@link #duplicate()}, {@link #slice()}, or + * {@link #asReadOnlyBuffer()}. They are useful especially when you broadcast the same messages to + * multiple {@link IoSession}s. Please note that the buffer derived from and its derived buffers are + * not both auto-expandable neither auto-shrinkable. Trying to call {@link #setAutoExpand(boolean)} + * or {@link #setAutoShrink(boolean)} with true parameter will raise an + * {@link IllegalStateException}. + *

+ * + *

Changing Buffer Allocation Policy

+ *

+ * {@link IoBufferAllocator} interface lets you override the default buffer management behavior. + * There are two allocators provided out-of-the-box: + *

    + *
  • {@link SimpleBufferAllocator} (default)
  • + *
  • {@link CachedBufferAllocator}
  • + *
+ * You can implement your own allocator and use it by calling + * {@link #setAllocator(IoBufferAllocator)}. + *

+ * + * @author The Apache MINA Project (dev@mina.apache.org) + * @version $Rev: 748525 $, $Date: 2009-02-27 14:45:31 +0100 (Fri, 27 Feb 2009) $ + */ +public abstract class IoBuffer implements Comparable { + /** The allocator used to create new buffers */ + private static IoBufferAllocator allocator = new SimpleBufferAllocator(); + + /** A flag indicating which type of buffer we are using : heap or direct */ + private static boolean useDirectBuffer = false; + + /** + * Returns the allocator used by existing and new buffers + */ + public static IoBufferAllocator getAllocator() { + return allocator; + } + + /** + * Sets the allocator used by existing and new buffers + */ + public static void setAllocator(IoBufferAllocator newAllocator) { + if (newAllocator == null) { + throw new NullPointerException("allocator"); + } + + IoBufferAllocator oldAllocator = allocator; + + allocator = newAllocator; + + if (null != oldAllocator) { + oldAllocator.dispose(); + } + } + + /** + * Returns true if and only if a direct buffer is allocated by default when the type of + * the new buffer is not specified. The default value is false. + */ + public static boolean isUseDirectBuffer() { + return useDirectBuffer; + } + + /** + * Sets if a direct buffer should be allocated by default when the type of the new buffer is not + * specified. The default value is false. + */ + public static void setUseDirectBuffer(boolean useDirectBuffer) { + IoBuffer.useDirectBuffer = useDirectBuffer; + } + + /** + * Returns the direct or heap buffer which is capable to store the specified amount of bytes. + * + * @param capacity the capacity of the buffer + * + * @see #setUseDirectBuffer(boolean) + */ + public static IoBuffer allocate(int capacity) { + return allocate(capacity, useDirectBuffer); + } + + /** + * Returns the buffer which is capable of the specified size. + * + * @param capacity the capacity of the buffer + * @param direct true to get a direct buffer, false to get a heap buffer. + */ + public static IoBuffer allocate(int capacity, boolean direct) { + if (capacity < 0) { + throw new IllegalArgumentException("capacity: " + capacity); + } + + return allocator.allocate(capacity, direct); + } + + /** + * Wraps the specified NIO {@link ByteBuffer} into MINA buffer. + */ + public static IoBuffer wrap(ByteBuffer nioBuffer) { + return allocator.wrap(nioBuffer); + } + + /** + * Wraps the specified byte array into MINA heap buffer. + */ + public static IoBuffer wrap(byte[] byteArray) { + return wrap(ByteBuffer.wrap(byteArray)); + } + + /** + * Wraps the specified byte array into MINA heap buffer. + */ + public static IoBuffer wrap(byte[] byteArray, int offset, int length) { + return wrap(ByteBuffer.wrap(byteArray, offset, length)); + } + + /** + * Normalizes the specified capacity of the buffer to power of 2, which is often helpful for + * optimal memory usage and performance. If it is greater than or equal to + * {@link Integer#MAX_VALUE}, it returns {@link Integer#MAX_VALUE}. If it is zero, it returns + * zero. + */ + protected static int normalizeCapacity(int requestedCapacity) { + switch (requestedCapacity) { + case 0: + case 1 << 0: + case 1 << 1: + case 1 << 2: + case 1 << 3: + case 1 << 4: + case 1 << 5: + case 1 << 6: + case 1 << 7: + case 1 << 8: + case 1 << 9: + case 1 << 10: + case 1 << 11: + case 1 << 12: + case 1 << 13: + case 1 << 14: + case 1 << 15: + case 1 << 16: + case 1 << 17: + case 1 << 18: + case 1 << 19: + case 1 << 21: + case 1 << 22: + case 1 << 23: + case 1 << 24: + case 1 << 25: + case 1 << 26: + case 1 << 27: + case 1 << 28: + case 1 << 29: + case 1 << 30: + case Integer.MAX_VALUE: + return requestedCapacity; + } + + int newCapacity = 1; + while (newCapacity < requestedCapacity) { + newCapacity <<= 1; + if (newCapacity < 0) { + return Integer.MAX_VALUE; + } + } + return newCapacity; + } + + /** + * Creates a new instance. This is an empty constructor. + */ + protected IoBuffer() {} + + /** + * Declares this buffer and all its derived buffers are not used anymore so that it can be reused + * by some {@link IoBufferAllocator} implementations. It is not mandatory to call this method, but + * you might want to invoke this method for maximum performance. + */ + public abstract void free(); + + /** + * Returns the underlying NIO buffer instance. + */ + public abstract ByteBuffer buf(); + + /** + * @see ByteBuffer#isDirect() + */ + public abstract boolean isDirect(); + + /** + * returns true if and only if this buffer is derived from other buffer via + * {@link #duplicate()}, {@link #slice()} or {@link #asReadOnlyBuffer()}. + */ + public abstract boolean isDerived(); + + /** + * @see ByteBuffer#isReadOnly() + */ + public abstract boolean isReadOnly(); + + /** + * Returns the minimum capacity of this buffer which is used to determine the new capacity of the + * buffer shrunk by {@link #compact()} and {@link #shrink()} operation. The default value is the + * initial capacity of the buffer. + */ + public abstract int minimumCapacity(); + + /** + * Sets the minimum capacity of this buffer which is used to determine the new capacity of the + * buffer shrunk by {@link #compact()} and {@link #shrink()} operation. The default value is the + * initial capacity of the buffer. + */ + public abstract IoBuffer minimumCapacity(int minimumCapacity); + + /** + * @see ByteBuffer#capacity() + */ + public abstract int capacity(); + + /** + * Increases the capacity of this buffer. If the new capacity is less than or equal to the current + * capacity, this method returns silently. If the new capacity is greater than the current + * capacity, the buffer is reallocated while retaining the position, limit, mark and the content + * of the buffer. + */ + public abstract IoBuffer capacity(int newCapacity); + + /** + * Returns true if and only if autoExpand is turned on. + */ + public abstract boolean isAutoExpand(); + + /** + * Turns on or off autoExpand. + */ + public abstract IoBuffer setAutoExpand(boolean autoExpand); + + /** + * Returns true if and only if autoShrink is turned on. + */ + public abstract boolean isAutoShrink(); + + /** + * Turns on or off autoShrink. + */ + public abstract IoBuffer setAutoShrink(boolean autoShrink); + + /** + * Changes the capacity and limit of this buffer so this buffer get the specified + * expectedRemaining room from the current position. This method works even if you didn't + * set autoExpand to true. + */ + public abstract IoBuffer expand(int expectedRemaining); + + /** + * Changes the capacity and limit of this buffer so this buffer get the specified + * expectedRemaining room from the specified position. This method works even if + * you didn't set autoExpand to true. + */ + public abstract IoBuffer expand(int position, int expectedRemaining); + + /** + * Changes the capacity of this buffer so this buffer occupies as less memory as possible while + * retaining the position, limit and the buffer content between the position and limit. The + * capacity of the buffer never becomes less than {@link #minimumCapacity()}. The mark is + * discarded once the capacity changes. + */ + public abstract IoBuffer shrink(); + + /** + * @see java.nio.Buffer#position() + */ + public abstract int position(); + + /** + * @see java.nio.Buffer#position(int) + */ + public abstract IoBuffer position(int newPosition); + + /** + * @see java.nio.Buffer#limit() + */ + public abstract int limit(); + + /** + * @see java.nio.Buffer#limit(int) + */ + public abstract IoBuffer limit(int newLimit); + + /** + * @see java.nio.Buffer#mark() + */ + public abstract IoBuffer mark(); + + /** + * Returns the position of the current mark. This method returns -1 if no mark is set. + */ + public abstract int markValue(); + + /** + * @see java.nio.Buffer#reset() + */ + public abstract IoBuffer reset(); + + /** + * @see java.nio.Buffer#clear() + */ + public abstract IoBuffer clear(); + + /** + * Clears this buffer and fills its content with NUL. The position is set to zero, the + * limit is set to the capacity, and the mark is discarded. + */ + public abstract IoBuffer sweep(); + + /** + * double Clears this buffer and fills its content with value. The position is set to + * zero, the limit is set to the capacity, and the mark is discarded. + */ + public abstract IoBuffer sweep(byte value); + + /** + * @see java.nio.Buffer#flip() + */ + public abstract IoBuffer flip(); + + /** + * @see java.nio.Buffer#rewind() + */ + public abstract IoBuffer rewind(); + + /** + * @see java.nio.Buffer#remaining() + */ + public abstract int remaining(); + + /** + * @see java.nio.Buffer#hasRemaining() + */ + public abstract boolean hasRemaining(); + + /** + * @see ByteBuffer#duplicate() + */ + public abstract IoBuffer duplicate(); + + /** + * @see ByteBuffer#slice() + */ + public abstract IoBuffer slice(); + + /** + * @see ByteBuffer#asReadOnlyBuffer() + */ + public abstract IoBuffer asReadOnlyBuffer(); + + /** + * @see ByteBuffer#hasArray() + */ + public abstract boolean hasArray(); + + /** + * @see ByteBuffer#array() + */ + public abstract byte[] array(); + + /** + * @see ByteBuffer#arrayOffset() + */ + public abstract int arrayOffset(); + + /** + * @see ByteBuffer#get() + */ + public abstract byte get(); + + /** + * Reads one unsigned byte as a short integer. + */ + public abstract short getUnsigned(); + + /** + * @see ByteBuffer#put(byte) + */ + public abstract IoBuffer put(byte b); + + /** + * @see ByteBuffer#get(int) + */ + public abstract byte get(int index); + + /** + * Reads one byte as an unsigned short integer. + */ + public abstract short getUnsigned(int index); + + /** + * @see ByteBuffer#put(int, byte) + */ + public abstract IoBuffer put(int index, byte b); + + /** + * @see ByteBuffer#get(byte[], int, int) + */ + public abstract IoBuffer get(byte[] dst, int offset, int length); + + /** + * @see ByteBuffer#get(byte[]) + */ + public abstract IoBuffer get(byte[] dst); + + /** + * TODO document me. + */ + public abstract IoBuffer getSlice(int index, int length); + + /** + * TODO document me. + */ + public abstract IoBuffer getSlice(int length); + + /** + * Writes the content of the specified src into this buffer. + */ + public abstract IoBuffer put(ByteBuffer src); + + /** + * Writes the content of the specified src into this buffer. + */ + public abstract IoBuffer put(IoBuffer src); + + /** + * @see ByteBuffer#put(byte[], int, int) + */ + public abstract IoBuffer put(byte[] src, int offset, int length); + + /** + * @see ByteBuffer#put(byte[]) + */ + public abstract IoBuffer put(byte[] src); + + /** + * @see ByteBuffer#compact() + */ + public abstract IoBuffer compact(); + + /** + * @see ByteBuffer#order() + */ + public abstract ByteOrder order(); + + /** + * @see ByteBuffer#order(ByteOrder) + */ + public abstract IoBuffer order(ByteOrder bo); + + /** + * @see ByteBuffer#getChar() + */ + public abstract char getChar(); + + /** + * @see ByteBuffer#putChar(char) + */ + public abstract IoBuffer putChar(char value); + + /** + * @see ByteBuffer#getChar(int) + */ + public abstract char getChar(int index); + + /** + * @see ByteBuffer#putChar(int, char) + */ + public abstract IoBuffer putChar(int index, char value); + + /** + * @see ByteBuffer#asCharBuffer() + */ + public abstract CharBuffer asCharBuffer(); + + /** + * @see ByteBuffer#getShort() + */ + public abstract short getShort(); + + /** + * Reads two bytes unsigned integer. + */ + public abstract int getUnsignedShort(); + + /** + * @see ByteBuffer#putShort(short) + */ + public abstract IoBuffer putShort(short value); + + /** + * @see ByteBuffer#getShort() + */ + public abstract short getShort(int index); + + /** + * Reads two bytes unsigned integer. + */ + public abstract int getUnsignedShort(int index); + + /** + * @see ByteBuffer#putShort(int, short) + */ + public abstract IoBuffer putShort(int index, short value); + + /** + * @see ByteBuffer#asShortBuffer() + */ + public abstract ShortBuffer asShortBuffer(); + + /** + * @see ByteBuffer#getInt() + */ + public abstract int getInt(); + + /** + * Reads four bytes unsigned integer. + */ + public abstract long getUnsignedInt(); + + /** + * Relative get method for reading a medium int value. + * + *

+ * Reads the next three bytes at this buffer's current position, composing them into an int value + * according to the current byte order, and then increments the position by three. + *

+ * + * @return The medium int value at the buffer's current position + */ + public abstract int getMediumInt(); + + /** + * Relative get method for reading an unsigned medium int value. + * + *

+ * Reads the next three bytes at this buffer's current position, composing them into an int value + * according to the current byte order, and then increments the position by three. + *

+ * + * @return The unsigned medium int value at the buffer's current position + */ + public abstract int getUnsignedMediumInt(); + + /** + * Absolute get method for reading a medium int value. + * + *

+ * Reads the next three bytes at this buffer's current position, composing them into an int value + * according to the current byte order. + *

+ * + * @param index The index from which the medium int will be read + * @return The medium int value at the given index + * + * @throws IndexOutOfBoundsException If index is negative or not smaller than the + * buffer's limit + */ + public abstract int getMediumInt(int index); + + /** + * Absolute get method for reading an unsigned medium int value. + * + *

+ * Reads the next three bytes at this buffer's current position, composing them into an int value + * according to the current byte order. + *

+ * + * @param index The index from which the unsigned medium int will be read + * @return The unsigned medium int value at the given index + * + * @throws IndexOutOfBoundsException If index is negative or not smaller than the + * buffer's limit + */ + public abstract int getUnsignedMediumInt(int index); + + /** + * Relative put method for writing a medium int value. + * + *

+ * Writes three bytes containing the given int value, in the current byte order, into this buffer + * at the current position, and then increments the position by three. + *

+ * + * @param value The medium int value to be written + * + * @return This buffer + * + * @throws BufferOverflowException If there are fewer than three bytes remaining in this buffer + * + * @throws ReadOnlyBufferException If this buffer is read-only + */ + public abstract IoBuffer putMediumInt(int value); + + /** + * Absolute put method for writing a medium int value. + * + *

+ * Writes three bytes containing the given int value, in the current byte order, into this buffer + * at the given index. + *

+ * + * @param index The index at which the bytes will be written + * + * @param value The medium int value to be written + * + * @return This buffer + * + * @throws IndexOutOfBoundsException If index is negative or not smaller than the + * buffer's limit, minus three + * + * @throws ReadOnlyBufferException If this buffer is read-only + */ + public abstract IoBuffer putMediumInt(int index, int value); + + /** + * @see ByteBuffer#putInt(int) + */ + public abstract IoBuffer putInt(int value); + + /** + * @see ByteBuffer#getInt(int) + */ + public abstract int getInt(int index); + + /** + * Reads four bytes unsigned integer. + */ + public abstract long getUnsignedInt(int index); + + /** + * @see ByteBuffer#putInt(int, int) + */ + public abstract IoBuffer putInt(int index, int value); + + /** + * @see ByteBuffer#asIntBuffer() + */ + public abstract IntBuffer asIntBuffer(); + + /** + * @see ByteBuffer#getLong() + */ + public abstract long getLong(); + + /** + * @see ByteBuffer#putLong(int, long) + */ + public abstract IoBuffer putLong(long value); + + /** + * @see ByteBuffer#getLong(int) + */ + public abstract long getLong(int index); + + /** + * @see ByteBuffer#putLong(int, long) + */ + public abstract IoBuffer putLong(int index, long value); + + /** + * @see ByteBuffer#asLongBuffer() + */ + public abstract LongBuffer asLongBuffer(); + + /** + * @see ByteBuffer#getFloat() + */ + public abstract float getFloat(); + + /** + * @see ByteBuffer#putFloat(float) + */ + public abstract IoBuffer putFloat(float value); + + /** + * @see ByteBuffer#getFloat(int) + */ + public abstract float getFloat(int index); + + /** + * @see ByteBuffer#putFloat(int, float) + */ + public abstract IoBuffer putFloat(int index, float value); + + /** + * @see ByteBuffer#asFloatBuffer() + */ + public abstract FloatBuffer asFloatBuffer(); + + /** + * @see ByteBuffer#getDouble() + */ + public abstract double getDouble(); + + /** + * @see ByteBuffer#putDouble(double) + */ + public abstract IoBuffer putDouble(double value); + + /** + * @see ByteBuffer#getDouble(int) + */ + public abstract double getDouble(int index); + + /** + * @see ByteBuffer#putDouble(int, double) + */ + public abstract IoBuffer putDouble(int index, double value); + + /** + * @see ByteBuffer#asDoubleBuffer() + */ + public abstract DoubleBuffer asDoubleBuffer(); + + /** + * Returns an {@link InputStream} that reads the data from this buffer. {@link InputStream#read()} + * returns -1 if the buffer position reaches to the limit. + */ + public abstract InputStream asInputStream(); + + /** + * Returns an {@link OutputStream} that appends the data into this buffer. Please note that the + * {@link OutputStream#write(int)} will throw a {@link BufferOverflowException} instead of an + * {@link IOException} in case of buffer overflow. Please set autoExpand property by + * calling {@link #setAutoExpand(boolean)} to prevent the unexpected runtime exception. + */ + public abstract OutputStream asOutputStream(); + + /** + * Returns hexdump of this buffer. The data and pointer are not changed as a result of this method + * call. + * + * @return hexidecimal representation of this buffer + */ + public abstract String getHexDump(); + + /** + * Return hexdump of this buffer with limited length. + * + * @param lengthLimit The maximum number of bytes to dump from the current buffer position. + * @return hexidecimal representation of this buffer + */ + public abstract String getHexDump(int lengthLimit); + + // ////////////////////////////// + // String getters and putters // + // ////////////////////////////// + + /** + * Reads a NUL-terminated string from this buffer using the specified + * decoder and returns it. This method reads until the limit of this buffer if no + * NUL is found. + */ + public abstract String getString(CharsetDecoder decoder) throws CharacterCodingException; + + /** + * Reads a NUL-terminated string from this buffer using the specified + * decoder and returns it. + * + * @param fieldSize the maximum number of bytes to read + */ + public abstract String getString(int fieldSize, CharsetDecoder decoder) + throws CharacterCodingException; + + /** + * Writes the content of in into this buffer using the specified encoder + * . This method doesn't terminate string with NUL. You have to do it by yourself. + * + * @throws BufferOverflowException if the specified string doesn't fit + */ + public abstract IoBuffer putString(CharSequence val, CharsetEncoder encoder) + throws CharacterCodingException; + + /** + * Writes the content of in into this buffer as a NUL-terminated string + * using the specified encoder. + *

+ * If the charset name of the encoder is UTF-16, you cannot specify odd fieldSize, + * and this method will append two NULs as a terminator. + *

+ * Please note that this method doesn't terminate with NUL if the input string is + * longer than fieldSize. + * + * @param fieldSize the maximum number of bytes to write + */ + public abstract IoBuffer putString(CharSequence val, int fieldSize, CharsetEncoder encoder) + throws CharacterCodingException; + + /** + * Reads a string which has a 16-bit length field before the actual encoded string, using the + * specified decoder and returns it. This method is a shortcut for + * getPrefixedString(2, decoder). + */ + public abstract String getPrefixedString(CharsetDecoder decoder) throws CharacterCodingException; + + /** + * Reads a string which has a length field before the actual encoded string, using the specified + * decoder and returns it. + * + * @param prefixLength the length of the length field (1, 2, or 4) + */ + public abstract String getPrefixedString(int prefixLength, CharsetDecoder decoder) + throws CharacterCodingException; + + /** + * Writes the content of in into this buffer as a string which has a 16-bit length + * field before the actual encoded string, using the specified encoder. This method + * is a shortcut for putPrefixedString(in, 2, 0, encoder). + * + * @throws BufferOverflowException if the specified string doesn't fit + */ + public abstract IoBuffer putPrefixedString(CharSequence in, CharsetEncoder encoder) + throws CharacterCodingException; + + /** + * Writes the content of in into this buffer as a string which has a 16-bit length + * field before the actual encoded string, using the specified encoder. This method + * is a shortcut for putPrefixedString(in, prefixLength, 0, encoder). + * + * @param prefixLength the length of the length field (1, 2, or 4) + * + * @throws BufferOverflowException if the specified string doesn't fit + */ + public abstract IoBuffer putPrefixedString(CharSequence in, int prefixLength, + CharsetEncoder encoder) throws CharacterCodingException; + + /** + * Writes the content of in into this buffer as a string which has a 16-bit length + * field before the actual encoded string, using the specified encoder. This method + * is a shortcut for putPrefixedString(in, prefixLength, padding, ( byte ) 0, encoder) . + * + * @param prefixLength the length of the length field (1, 2, or 4) + * @param padding the number of padded NULs (1 (or 0), 2, or 4) + * + * @throws BufferOverflowException if the specified string doesn't fit + */ + public abstract IoBuffer putPrefixedString(CharSequence in, int prefixLength, int padding, + CharsetEncoder encoder) throws CharacterCodingException; + + /** + * Writes the content of in into this buffer as a string which has a 16-bit length + * field before the actual encoded string, using the specified encoder. + * + * @param prefixLength the length of the length field (1, 2, or 4) + * @param padding the number of padded bytes (1 (or 0), 2, or 4) + * @param padValue the value of padded bytes + * + * @throws BufferOverflowException if the specified string doesn't fit + */ + public abstract IoBuffer putPrefixedString(CharSequence val, int prefixLength, int padding, + byte padValue, CharsetEncoder encoder) throws CharacterCodingException; + + /** + * Reads a Java object from the buffer using the context {@link ClassLoader} of the current + * thread. + */ + public abstract Object getObject() throws ClassNotFoundException; + + /** + * Reads a Java object from the buffer using the specified classLoader. + */ + public abstract Object getObject(final ClassLoader classLoader) throws ClassNotFoundException; + + /** + * Writes the specified Java object to the buffer. + */ + public abstract IoBuffer putObject(Object o); + + /** + * Returns true if this buffer contains a data which has a data length as a prefix and + * the buffer has remaining data as enough as specified in the data length field. This method is + * identical with prefixedDataAvailable( prefixLength, Integer.MAX_VALUE ). Please not + * that using this method can allow DoS (Denial of Service) attack in case the remote peer sends + * too big data length value. It is recommended to use {@link #prefixedDataAvailable(int, int)} + * instead. + * + * @param prefixLength the length of the prefix field (1, 2, or 4) + * + * @throws IllegalArgumentException if prefixLength is wrong + * @throws BufferDataException if data length is negative + */ + public abstract boolean prefixedDataAvailable(int prefixLength); + + /** + * Returns true if this buffer contains a data which has a data length as a prefix and + * the buffer has remaining data as enough as specified in the data length field. + * + * @param prefixLength the length of the prefix field (1, 2, or 4) + * @param maxDataLength the allowed maximum of the read data length + * + * @throws IllegalArgumentException if prefixLength is wrong + * @throws BufferDataException if data length is negative or greater then maxDataLength + */ + public abstract boolean prefixedDataAvailable(int prefixLength, int maxDataLength); + + // /////////////////// + // IndexOf methods // + // /////////////////// + + /** + * Returns the first occurence position of the specified byte from the current position to the + * current limit. + * + * @return -1 if the specified byte is not found + */ + public abstract int indexOf(byte b); + + // //////////////////////// + // Skip or fill methods // + // //////////////////////// + + /** + * Forwards the position of this buffer as the specified size bytes. + */ + public abstract IoBuffer skip(int size); + + /** + * Fills this buffer with the specified value. This method moves buffer position forward. + */ + public abstract IoBuffer fill(byte value, int size); + + /** + * Fills this buffer with the specified value. This method does not change buffer position. + */ + public abstract IoBuffer fillAndReset(byte value, int size); + + /** + * Fills this buffer with NUL (0x00). This method moves buffer position forward. + */ + public abstract IoBuffer fill(int size); + + /** + * Fills this buffer with NUL (0x00). This method does not change buffer position. + */ + public abstract IoBuffer fillAndReset(int size); + + // //////////////////////// + // Enum methods // + // //////////////////////// + + /** + * Reads a byte from the buffer and returns the correlating enum constant defined by the specified + * enum type. + * + * @param The enum type to return + * @param enumClass The enum's class object + */ + public abstract > E getEnum(Class enumClass); + + /** + * Reads a byte from the buffer and returns the correlating enum constant defined by the specified + * enum type. + * + * @param The enum type to return + * @param index the index from which the byte will be read + * @param enumClass The enum's class object + */ + public abstract > E getEnum(int index, Class enumClass); + + /** + * Reads a short from the buffer and returns the correlating enum constant defined by the + * specified enum type. + * + * @param The enum type to return + * @param enumClass The enum's class object + */ + public abstract > E getEnumShort(Class enumClass); + + /** + * Reads a short from the buffer and returns the correlating enum constant defined by the + * specified enum type. + * + * @param The enum type to return + * @param index the index from which the bytes will be read + * @param enumClass The enum's class object + */ + public abstract > E getEnumShort(int index, Class enumClass); + + /** + * Reads an int from the buffer and returns the correlating enum constant defined by the specified + * enum type. + * + * @param The enum type to return + * @param enumClass The enum's class object + */ + public abstract > E getEnumInt(Class enumClass); + + /** + * Reads an int from the buffer and returns the correlating enum constant defined by the specified + * enum type. + * + * @param The enum type to return + * @param index the index from which the bytes will be read + * @param enumClass The enum's class object + */ + public abstract > E getEnumInt(int index, Class enumClass); + + /** + * Writes an enum's ordinal value to the buffer as a byte. + * + * @param e The enum to write to the buffer + */ + public abstract IoBuffer putEnum(Enum e); + + /** + * Writes an enum's ordinal value to the buffer as a byte. + * + * @param index The index at which the byte will be written + * @param e The enum to write to the buffer + */ + public abstract IoBuffer putEnum(int index, Enum e); + + /** + * Writes an enum's ordinal value to the buffer as a short. + * + * @param e The enum to write to the buffer + */ + public abstract IoBuffer putEnumShort(Enum e); + + /** + * Writes an enum's ordinal value to the buffer as a short. + * + * @param index The index at which the bytes will be written + * @param e The enum to write to the buffer + */ + public abstract IoBuffer putEnumShort(int index, Enum e); + + /** + * Writes an enum's ordinal value to the buffer as an integer. + * + * @param e The enum to write to the buffer + */ + public abstract IoBuffer putEnumInt(Enum e); + + /** + * Writes an enum's ordinal value to the buffer as an integer. + * + * @param index The index at which the bytes will be written + * @param e The enum to write to the buffer + */ + public abstract IoBuffer putEnumInt(int index, Enum e); + + // //////////////////////// + // EnumSet methods // + // //////////////////////// + + /** + * Reads a byte sized bit vector and converts it to an {@link EnumSet}. + * + *

+ * Each bit is mapped to a value in the specified enum. The least significant bit maps to the + * first entry in the specified enum and each subsequent bit maps to each subsequent bit as mapped + * to the subsequent enum value. + *

+ * + * @param the enum type + * @param enumClass the enum class used to create the EnumSet + * @return the EnumSet representation of the bit vector + */ + public abstract > EnumSet getEnumSet(Class enumClass); + + /** + * Reads a byte sized bit vector and converts it to an {@link EnumSet}. + * + * @see #getEnumSet(Class) + * @param the enum type + * @param index the index from which the byte will be read + * @param enumClass the enum class used to create the EnumSet + * @return the EnumSet representation of the bit vector + */ + public abstract > EnumSet getEnumSet(int index, Class enumClass); + + /** + * Reads a short sized bit vector and converts it to an {@link EnumSet}. + * + * @see #getEnumSet(Class) + * @param the enum type + * @param enumClass the enum class used to create the EnumSet + * @return the EnumSet representation of the bit vector + */ + public abstract > EnumSet getEnumSetShort(Class enumClass); + + /** + * Reads a short sized bit vector and converts it to an {@link EnumSet}. + * + * @see #getEnumSet(Class) + * @param the enum type + * @param index the index from which the bytes will be read + * @param enumClass the enum class used to create the EnumSet + * @return the EnumSet representation of the bit vector + */ + public abstract > EnumSet getEnumSetShort(int index, Class enumClass); + + /** + * Reads an int sized bit vector and converts it to an {@link EnumSet}. + * + * @see #getEnumSet(Class) + * @param the enum type + * @param enumClass the enum class used to create the EnumSet + * @return the EnumSet representation of the bit vector + */ + public abstract > EnumSet getEnumSetInt(Class enumClass); + + /** + * Reads an int sized bit vector and converts it to an {@link EnumSet}. + * + * @see #getEnumSet(Class) + * @param the enum type + * @param index the index from which the bytes will be read + * @param enumClass the enum class used to create the EnumSet + * @return the EnumSet representation of the bit vector + */ + public abstract > EnumSet getEnumSetInt(int index, Class enumClass); + + /** + * Reads a long sized bit vector and converts it to an {@link EnumSet}. + * + * @see #getEnumSet(Class) + * @param the enum type + * @param enumClass the enum class used to create the EnumSet + * @return the EnumSet representation of the bit vector + */ + public abstract > EnumSet getEnumSetLong(Class enumClass); + + /** + * Reads a long sized bit vector and converts it to an {@link EnumSet}. + * + * @see #getEnumSet(Class) + * @param the enum type + * @param index the index from which the bytes will be read + * @param enumClass the enum class used to create the EnumSet + * @return the EnumSet representation of the bit vector + */ + public abstract > EnumSet getEnumSetLong(int index, Class enumClass); + + /** + * Writes the specified {@link Set} to the buffer as a byte sized bit vector. + * + * @param the enum type of the Set + * @param set the enum set to write to the buffer + */ + public abstract > IoBuffer putEnumSet(Set set); + + /** + * Writes the specified {@link Set} to the buffer as a byte sized bit vector. + * + * @param the enum type of the Set + * @param index the index at which the byte will be written + * @param set the enum set to write to the buffer + */ + public abstract > IoBuffer putEnumSet(int index, Set set); + + /** + * Writes the specified {@link Set} to the buffer as a short sized bit vector. + * + * @param the enum type of the Set + * @param set the enum set to write to the buffer + */ + public abstract > IoBuffer putEnumSetShort(Set set); + + /** + * Writes the specified {@link Set} to the buffer as a short sized bit vector. + * + * @param the enum type of the Set + * @param index the index at which the bytes will be written + * @param set the enum set to write to the buffer + */ + public abstract > IoBuffer putEnumSetShort(int index, Set set); + + /** + * Writes the specified {@link Set} to the buffer as an int sized bit vector. + * + * @param the enum type of the Set + * @param set the enum set to write to the buffer + */ + public abstract > IoBuffer putEnumSetInt(Set set); + + /** + * Writes the specified {@link Set} to the buffer as an int sized bit vector. + * + * @param the enum type of the Set + * @param index the index at which the bytes will be written + * @param set the enum set to write to the buffer + */ + public abstract > IoBuffer putEnumSetInt(int index, Set set); + + /** + * Writes the specified {@link Set} to the buffer as a long sized bit vector. + * + * @param the enum type of the Set + * @param set the enum set to write to the buffer + */ + public abstract > IoBuffer putEnumSetLong(Set set); + + /** + * Writes the specified {@link Set} to the buffer as a long sized bit vector. + * + * @param the enum type of the Set + * @param index the index at which the bytes will be written + * @param set the enum set to write to the buffer + */ + public abstract > IoBuffer putEnumSetLong(int index, Set set); +} diff --git a/src/main/java/com/google/code/yanf4j/buffer/IoBufferAllocator.java b/src/main/java/com/google/code/yanf4j/buffer/IoBufferAllocator.java index 48c825862..07f8b5b83 100644 --- a/src/main/java/com/google/code/yanf4j/buffer/IoBufferAllocator.java +++ b/src/main/java/com/google/code/yanf4j/buffer/IoBufferAllocator.java @@ -1,64 +1,52 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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 com.google.code.yanf4j.buffer; - -import java.nio.ByteBuffer; - -/** - * Allocates {@link IoBuffer}s and manages them. Please implement this interface - * if you need more advanced memory management scheme. - * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev: 671827 $, $Date: 2008-06-26 10:49:48 +0200 (Thu, 26 Jun 2008) - * $ - */ -public interface IoBufferAllocator { - /** - * Returns the buffer which is capable of the specified size. - * - * @param capacity - * the capacity of the buffer - * @param direct - * true to get a direct buffer, false to get a - * heap buffer. - */ - IoBuffer allocate(int capacity, boolean direct); - - /** - * Returns the NIO buffer which is capable of the specified size. - * - * @param capacity - * the capacity of the buffer - * @param direct - * true to get a direct buffer, false to get a - * heap buffer. - */ - ByteBuffer allocateNioBuffer(int capacity, boolean direct); - - /** - * Wraps the specified NIO {@link ByteBuffer} into MINA buffer. - */ - IoBuffer wrap(ByteBuffer nioBuffer); - - /** - * Dispose of this allocator. - */ - void dispose(); -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF 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 com.google.code.yanf4j.buffer; + +import java.nio.ByteBuffer; + +/** + * Allocates {@link IoBuffer}s and manages them. Please implement this interface if you need more + * advanced memory management scheme. + * + * @author The Apache MINA Project (dev@mina.apache.org) + * @version $Rev: 671827 $, $Date: 2008-06-26 10:49:48 +0200 (Thu, 26 Jun 2008) $ + */ +public interface IoBufferAllocator { + /** + * Returns the buffer which is capable of the specified size. + * + * @param capacity the capacity of the buffer + * @param direct true to get a direct buffer, false to get a heap buffer. + */ + IoBuffer allocate(int capacity, boolean direct); + + /** + * Returns the NIO buffer which is capable of the specified size. + * + * @param capacity the capacity of the buffer + * @param direct true to get a direct buffer, false to get a heap buffer. + */ + ByteBuffer allocateNioBuffer(int capacity, boolean direct); + + /** + * Wraps the specified NIO {@link ByteBuffer} into MINA buffer. + */ + IoBuffer wrap(ByteBuffer nioBuffer); + + /** + * Dispose of this allocator. + */ + void dispose(); +} diff --git a/src/main/java/com/google/code/yanf4j/buffer/IoBufferHexDumper.java b/src/main/java/com/google/code/yanf4j/buffer/IoBufferHexDumper.java index 4a011f331..bf8fa399a 100644 --- a/src/main/java/com/google/code/yanf4j/buffer/IoBufferHexDumper.java +++ b/src/main/java/com/google/code/yanf4j/buffer/IoBufferHexDumper.java @@ -1,116 +1,105 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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 com.google.code.yanf4j.buffer; - -/** - * Provides utility methods to dump an {@link IoBuffer} into a hex formatted - * string. - * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev: 686598 $, $Date: 2008-08-17 12:58:23 +0200 (Sun, 17 Aug 2008) - * $ - */ -class IoBufferHexDumper { - - /** - * The high digits lookup table. - */ - private static final byte[] highDigits; - - /** - * The low digits lookup table. - */ - private static final byte[] lowDigits; - - /** - * Initialize lookup tables. - */ - static { - final byte[] digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'A', 'B', 'C', 'D', 'E', 'F'}; - - int i; - byte[] high = new byte[256]; - byte[] low = new byte[256]; - - for (i = 0; i < 256; i++) { - high[i] = digits[i >>> 4]; - low[i] = digits[i & 0x0F]; - } - - highDigits = high; - lowDigits = low; - } - - /** - * Dumps an {@link IoBuffer} to a hex formatted string. - * - * @param in - * the buffer to dump - * @param lengthLimit - * the limit at which hex dumping will stop - * @return a hex formatted string representation of the in - * {@link Iobuffer}. - */ - public static String getHexdump(IoBuffer in, int lengthLimit) { - if (lengthLimit == 0) { - throw new IllegalArgumentException( - "lengthLimit: " + lengthLimit + " (expected: 1+)"); - } - - boolean truncate = in.remaining() > lengthLimit; - int size; - if (truncate) { - size = lengthLimit; - } else { - size = in.remaining(); - } - - if (size == 0) { - return "empty"; - } - - StringBuilder out = new StringBuilder(in.remaining() * 3 - 1); - - int mark = in.position(); - - // fill the first - int byteValue = in.get() & 0xFF; - out.append((char) highDigits[byteValue]); - out.append((char) lowDigits[byteValue]); - size--; - - // and the others, too - for (; size > 0; size--) { - out.append(' '); - byteValue = in.get() & 0xFF; - out.append((char) highDigits[byteValue]); - out.append((char) lowDigits[byteValue]); - } - - in.position(mark); - - if (truncate) { - out.append("..."); - } - - return out.toString(); - } -} \ No newline at end of file +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF 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 com.google.code.yanf4j.buffer; + +/** + * Provides utility methods to dump an {@link IoBuffer} into a hex formatted string. + * + * @author The Apache MINA Project (dev@mina.apache.org) + * @version $Rev: 686598 $, $Date: 2008-08-17 12:58:23 +0200 (Sun, 17 Aug 2008) $ + */ +class IoBufferHexDumper { + + /** + * The high digits lookup table. + */ + private static final byte[] highDigits; + + /** + * The low digits lookup table. + */ + private static final byte[] lowDigits; + + /** + * Initialize lookup tables. + */ + static { + final byte[] digits = + {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + + int i; + byte[] high = new byte[256]; + byte[] low = new byte[256]; + + for (i = 0; i < 256; i++) { + high[i] = digits[i >>> 4]; + low[i] = digits[i & 0x0F]; + } + + highDigits = high; + lowDigits = low; + } + + /** + * Dumps an {@link IoBuffer} to a hex formatted string. + * + * @param in the buffer to dump + * @param lengthLimit the limit at which hex dumping will stop + * @return a hex formatted string representation of the in {@link Iobuffer}. + */ + public static String getHexdump(IoBuffer in, int lengthLimit) { + if (lengthLimit == 0) { + throw new IllegalArgumentException("lengthLimit: " + lengthLimit + " (expected: 1+)"); + } + + boolean truncate = in.remaining() > lengthLimit; + int size; + if (truncate) { + size = lengthLimit; + } else { + size = in.remaining(); + } + + if (size == 0) { + return "empty"; + } + + StringBuilder out = new StringBuilder(in.remaining() * 3 - 1); + + int mark = in.position(); + + // fill the first + int byteValue = in.get() & 0xFF; + out.append((char) highDigits[byteValue]); + out.append((char) lowDigits[byteValue]); + size--; + + // and the others, too + for (; size > 0; size--) { + out.append(' '); + byteValue = in.get() & 0xFF; + out.append((char) highDigits[byteValue]); + out.append((char) lowDigits[byteValue]); + } + + in.position(mark); + + if (truncate) { + out.append("..."); + } + + return out.toString(); + } +} diff --git a/src/main/java/com/google/code/yanf4j/buffer/IoBufferWrapper.java b/src/main/java/com/google/code/yanf4j/buffer/IoBufferWrapper.java index 75260c658..eb4a63a91 100644 --- a/src/main/java/com/google/code/yanf4j/buffer/IoBufferWrapper.java +++ b/src/main/java/com/google/code/yanf4j/buffer/IoBufferWrapper.java @@ -1,908 +1,891 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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 com.google.code.yanf4j.buffer; - -import java.io.FilterOutputStream; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.CharBuffer; -import java.nio.DoubleBuffer; -import java.nio.FloatBuffer; -import java.nio.IntBuffer; -import java.nio.LongBuffer; -import java.nio.ShortBuffer; -import java.nio.charset.CharacterCodingException; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CharsetEncoder; -import java.util.EnumSet; -import java.util.Set; - -/** - * A {@link IoBuffer} that wraps a buffer and proxies any operations to it. - *

- * You can think this class like a {@link FilterOutputStream}. All operations - * are proxied by default so that you can extend this class and override - * existing operations selectively. You can introduce new operations, too. - * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev: 671827 $, $Date: 2008-06-26 10:49:48 +0200 (Thu, 26 Jun 2008) - * $ - */ -public class IoBufferWrapper extends IoBuffer { - - /** - * The buffer proxied by this proxy. - */ - private final IoBuffer buf; - - /** - * Create a new instance. - * - * @param buf - * the buffer to be proxied - */ - protected IoBufferWrapper(IoBuffer buf) { - if (buf == null) { - throw new NullPointerException("buf"); - } - this.buf = buf; - } - - /** - * Returns the parent buffer that this buffer wrapped. - */ - public IoBuffer getParentBuffer() { - return buf; - } - - @Override - public boolean isDirect() { - return buf.isDirect(); - } - - @Override - public ByteBuffer buf() { - return buf.buf(); - } - - @Override - public int capacity() { - return buf.capacity(); - } - - @Override - public int position() { - return buf.position(); - } - - @Override - public IoBuffer position(int newPosition) { - buf.position(newPosition); - return this; - } - - @Override - public int limit() { - return buf.limit(); - } - - @Override - public IoBuffer limit(int newLimit) { - buf.limit(newLimit); - return this; - } - - @Override - public IoBuffer mark() { - buf.mark(); - return this; - } - - @Override - public IoBuffer reset() { - buf.reset(); - return this; - } - - @Override - public IoBuffer clear() { - buf.clear(); - return this; - } - - @Override - public IoBuffer sweep() { - buf.sweep(); - return this; - } - - @Override - public IoBuffer sweep(byte value) { - buf.sweep(value); - return this; - } - - @Override - public IoBuffer flip() { - buf.flip(); - return this; - } - - @Override - public IoBuffer rewind() { - buf.rewind(); - return this; - } - - @Override - public int remaining() { - return buf.remaining(); - } - - @Override - public boolean hasRemaining() { - return buf.hasRemaining(); - } - - @Override - public byte get() { - return buf.get(); - } - - @Override - public short getUnsigned() { - return buf.getUnsigned(); - } - - @Override - public IoBuffer put(byte b) { - buf.put(b); - return this; - } - - @Override - public byte get(int index) { - return buf.get(index); - } - - @Override - public short getUnsigned(int index) { - return buf.getUnsigned(index); - } - - @Override - public IoBuffer put(int index, byte b) { - buf.put(index, b); - return this; - } - - @Override - public IoBuffer get(byte[] dst, int offset, int length) { - buf.get(dst, offset, length); - return this; - } - - @Override - public IoBuffer getSlice(int index, int length) { - return buf.getSlice(index, length); - } - - @Override - public IoBuffer getSlice(int length) { - return buf.getSlice(length); - } - - @Override - public IoBuffer get(byte[] dst) { - buf.get(dst); - return this; - } - - @Override - public IoBuffer put(IoBuffer src) { - buf.put(src); - return this; - } - - @Override - public IoBuffer put(ByteBuffer src) { - buf.put(src); - return this; - } - - @Override - public IoBuffer put(byte[] src, int offset, int length) { - buf.put(src, offset, length); - return this; - } - - @Override - public IoBuffer put(byte[] src) { - buf.put(src); - return this; - } - - @Override - public IoBuffer compact() { - buf.compact(); - return this; - } - - @Override - public String toString() { - return buf.toString(); - } - - @Override - public int hashCode() { - return buf.hashCode(); - } - - @Override - public boolean equals(Object ob) { - return buf.equals(ob); - } - - public int compareTo(IoBuffer that) { - return buf.compareTo(that); - } - - @Override - public ByteOrder order() { - return buf.order(); - } - - @Override - public IoBuffer order(ByteOrder bo) { - buf.order(bo); - return this; - } - - @Override - public char getChar() { - return buf.getChar(); - } - - @Override - public IoBuffer putChar(char value) { - buf.putChar(value); - return this; - } - - @Override - public char getChar(int index) { - return buf.getChar(index); - } - - @Override - public IoBuffer putChar(int index, char value) { - buf.putChar(index, value); - return this; - } - - @Override - public CharBuffer asCharBuffer() { - return buf.asCharBuffer(); - } - - @Override - public short getShort() { - return buf.getShort(); - } - - @Override - public int getUnsignedShort() { - return buf.getUnsignedShort(); - } - - @Override - public IoBuffer putShort(short value) { - buf.putShort(value); - return this; - } - - @Override - public short getShort(int index) { - return buf.getShort(index); - } - - @Override - public int getUnsignedShort(int index) { - return buf.getUnsignedShort(index); - } - - @Override - public IoBuffer putShort(int index, short value) { - buf.putShort(index, value); - return this; - } - - @Override - public ShortBuffer asShortBuffer() { - return buf.asShortBuffer(); - } - - @Override - public int getInt() { - return buf.getInt(); - } - - @Override - public long getUnsignedInt() { - return buf.getUnsignedInt(); - } - - @Override - public IoBuffer putInt(int value) { - buf.putInt(value); - return this; - } - - @Override - public int getInt(int index) { - return buf.getInt(index); - } - - @Override - public long getUnsignedInt(int index) { - return buf.getUnsignedInt(index); - } - - @Override - public IoBuffer putInt(int index, int value) { - buf.putInt(index, value); - return this; - } - - @Override - public IntBuffer asIntBuffer() { - return buf.asIntBuffer(); - } - - @Override - public long getLong() { - return buf.getLong(); - } - - @Override - public IoBuffer putLong(long value) { - buf.putLong(value); - return this; - } - - @Override - public long getLong(int index) { - return buf.getLong(index); - } - - @Override - public IoBuffer putLong(int index, long value) { - buf.putLong(index, value); - return this; - } - - @Override - public LongBuffer asLongBuffer() { - return buf.asLongBuffer(); - } - - @Override - public float getFloat() { - return buf.getFloat(); - } - - @Override - public IoBuffer putFloat(float value) { - buf.putFloat(value); - return this; - } - - @Override - public float getFloat(int index) { - return buf.getFloat(index); - } - - @Override - public IoBuffer putFloat(int index, float value) { - buf.putFloat(index, value); - return this; - } - - @Override - public FloatBuffer asFloatBuffer() { - return buf.asFloatBuffer(); - } - - @Override - public double getDouble() { - return buf.getDouble(); - } - - @Override - public IoBuffer putDouble(double value) { - buf.putDouble(value); - return this; - } - - @Override - public double getDouble(int index) { - return buf.getDouble(index); - } - - @Override - public IoBuffer putDouble(int index, double value) { - buf.putDouble(index, value); - return this; - } - - @Override - public DoubleBuffer asDoubleBuffer() { - return buf.asDoubleBuffer(); - } - - @Override - public String getHexDump() { - return buf.getHexDump(); - } - - @Override - public String getString(int fieldSize, CharsetDecoder decoder) - throws CharacterCodingException { - return buf.getString(fieldSize, decoder); - } - - @Override - public String getString(CharsetDecoder decoder) - throws CharacterCodingException { - return buf.getString(decoder); - } - - @Override - public String getPrefixedString(CharsetDecoder decoder) - throws CharacterCodingException { - return buf.getPrefixedString(decoder); - } - - @Override - public String getPrefixedString(int prefixLength, CharsetDecoder decoder) - throws CharacterCodingException { - return buf.getPrefixedString(prefixLength, decoder); - } - - @Override - public IoBuffer putString(CharSequence in, int fieldSize, - CharsetEncoder encoder) throws CharacterCodingException { - buf.putString(in, fieldSize, encoder); - return this; - } - - @Override - public IoBuffer putString(CharSequence in, CharsetEncoder encoder) - throws CharacterCodingException { - buf.putString(in, encoder); - return this; - } - - @Override - public IoBuffer putPrefixedString(CharSequence in, CharsetEncoder encoder) - throws CharacterCodingException { - buf.putPrefixedString(in, encoder); - return this; - } - - @Override - public IoBuffer putPrefixedString(CharSequence in, int prefixLength, - CharsetEncoder encoder) throws CharacterCodingException { - buf.putPrefixedString(in, prefixLength, encoder); - return this; - } - - @Override - public IoBuffer putPrefixedString(CharSequence in, int prefixLength, - int padding, CharsetEncoder encoder) - throws CharacterCodingException { - buf.putPrefixedString(in, prefixLength, padding, encoder); - return this; - } - - @Override - public IoBuffer putPrefixedString(CharSequence in, int prefixLength, - int padding, byte padValue, CharsetEncoder encoder) - throws CharacterCodingException { - buf.putPrefixedString(in, prefixLength, padding, padValue, encoder); - return this; - } - - @Override - public IoBuffer skip(int size) { - buf.skip(size); - return this; - } - - @Override - public IoBuffer fill(byte value, int size) { - buf.fill(value, size); - return this; - } - - @Override - public IoBuffer fillAndReset(byte value, int size) { - buf.fillAndReset(value, size); - return this; - } - - @Override - public IoBuffer fill(int size) { - buf.fill(size); - return this; - } - - @Override - public IoBuffer fillAndReset(int size) { - buf.fillAndReset(size); - return this; - } - - @Override - public boolean isAutoExpand() { - return buf.isAutoExpand(); - } - - @Override - public IoBuffer setAutoExpand(boolean autoExpand) { - buf.setAutoExpand(autoExpand); - return this; - } - - @Override - public IoBuffer expand(int pos, int expectedRemaining) { - buf.expand(pos, expectedRemaining); - return this; - } - - @Override - public IoBuffer expand(int expectedRemaining) { - buf.expand(expectedRemaining); - return this; - } - - @Override - public Object getObject() throws ClassNotFoundException { - return buf.getObject(); - } - - @Override - public Object getObject(ClassLoader classLoader) - throws ClassNotFoundException { - return buf.getObject(classLoader); - } - - @Override - public IoBuffer putObject(Object o) { - buf.putObject(o); - return this; - } - - @Override - public InputStream asInputStream() { - return buf.asInputStream(); - } - - @Override - public OutputStream asOutputStream() { - return buf.asOutputStream(); - } - - @Override - public IoBuffer duplicate() { - return buf.duplicate(); - } - - @Override - public IoBuffer slice() { - return buf.slice(); - } - - @Override - public IoBuffer asReadOnlyBuffer() { - return buf.asReadOnlyBuffer(); - } - - @Override - public byte[] array() { - return buf.array(); - } - - @Override - public int arrayOffset() { - return buf.arrayOffset(); - } - - @Override - public int minimumCapacity() { - return buf.minimumCapacity(); - } - - @Override - public IoBuffer minimumCapacity(int minimumCapacity) { - buf.minimumCapacity(minimumCapacity); - return this; - } - - @Override - public IoBuffer capacity(int newCapacity) { - buf.capacity(newCapacity); - return this; - } - - @Override - public boolean isReadOnly() { - return buf.isReadOnly(); - } - - @Override - public int markValue() { - return buf.markValue(); - } - - @Override - public boolean hasArray() { - return buf.hasArray(); - } - - @Override - public void free() { - buf.free(); - } - - @Override - public boolean isDerived() { - return buf.isDerived(); - } - - @Override - public boolean isAutoShrink() { - return buf.isAutoShrink(); - } - - @Override - public IoBuffer setAutoShrink(boolean autoShrink) { - buf.setAutoShrink(autoShrink); - return this; - } - - @Override - public IoBuffer shrink() { - buf.shrink(); - return this; - } - - @Override - public int getMediumInt() { - return buf.getMediumInt(); - } - - @Override - public int getUnsignedMediumInt() { - return buf.getUnsignedMediumInt(); - } - - @Override - public int getMediumInt(int index) { - return buf.getMediumInt(index); - } - - @Override - public int getUnsignedMediumInt(int index) { - return buf.getUnsignedMediumInt(index); - } - - @Override - public IoBuffer putMediumInt(int value) { - buf.putMediumInt(value); - return this; - } - - @Override - public IoBuffer putMediumInt(int index, int value) { - buf.putMediumInt(index, value); - return this; - } - - @Override - public String getHexDump(int lengthLimit) { - return buf.getHexDump(lengthLimit); - } - - @Override - public boolean prefixedDataAvailable(int prefixLength) { - return buf.prefixedDataAvailable(prefixLength); - } - - @Override - public boolean prefixedDataAvailable(int prefixLength, int maxDataLength) { - return buf.prefixedDataAvailable(prefixLength, maxDataLength); - } - - @Override - public int indexOf(byte b) { - return buf.indexOf(b); - } - - @Override - public > E getEnum(Class enumClass) { - return buf.getEnum(enumClass); - } - - @Override - public > E getEnum(int index, Class enumClass) { - return buf.getEnum(index, enumClass); - } - - @Override - public > E getEnumShort(Class enumClass) { - return buf.getEnumShort(enumClass); - } - - @Override - public > E getEnumShort(int index, Class enumClass) { - return buf.getEnumShort(index, enumClass); - } - - @Override - public > E getEnumInt(Class enumClass) { - return buf.getEnumInt(enumClass); - } - - @Override - public > E getEnumInt(int index, Class enumClass) { - return buf.getEnumInt(index, enumClass); - } - - @Override - public IoBuffer putEnum(Enum e) { - buf.putEnum(e); - return this; - } - - @Override - public IoBuffer putEnum(int index, Enum e) { - buf.putEnum(index, e); - return this; - } - - @Override - public IoBuffer putEnumShort(Enum e) { - buf.putEnumShort(e); - return this; - } - - @Override - public IoBuffer putEnumShort(int index, Enum e) { - buf.putEnumShort(index, e); - return this; - } - - @Override - public IoBuffer putEnumInt(Enum e) { - buf.putEnumInt(e); - return this; - } - - @Override - public IoBuffer putEnumInt(int index, Enum e) { - buf.putEnumInt(index, e); - return this; - } - - @Override - public > EnumSet getEnumSet(Class enumClass) { - return buf.getEnumSet(enumClass); - } - - @Override - public > EnumSet getEnumSet(int index, - Class enumClass) { - return buf.getEnumSet(index, enumClass); - } - - @Override - public > EnumSet getEnumSetShort(Class enumClass) { - return buf.getEnumSetShort(enumClass); - } - - @Override - public > EnumSet getEnumSetShort(int index, - Class enumClass) { - return buf.getEnumSetShort(index, enumClass); - } - - @Override - public > EnumSet getEnumSetInt(Class enumClass) { - return buf.getEnumSetInt(enumClass); - } - - @Override - public > EnumSet getEnumSetInt(int index, - Class enumClass) { - return buf.getEnumSetInt(index, enumClass); - } - - @Override - public > EnumSet getEnumSetLong(Class enumClass) { - return buf.getEnumSetLong(enumClass); - } - - @Override - public > EnumSet getEnumSetLong(int index, - Class enumClass) { - return buf.getEnumSetLong(index, enumClass); - } - - @Override - public > IoBuffer putEnumSet(Set set) { - buf.putEnumSet(set); - return this; - } - - @Override - public > IoBuffer putEnumSet(int index, Set set) { - buf.putEnumSet(index, set); - return this; - } - - @Override - public > IoBuffer putEnumSetShort(Set set) { - buf.putEnumSetShort(set); - return this; - } - - @Override - public > IoBuffer putEnumSetShort(int index, Set set) { - buf.putEnumSetShort(index, set); - return this; - } - - @Override - public > IoBuffer putEnumSetInt(Set set) { - buf.putEnumSetInt(set); - return this; - } - - @Override - public > IoBuffer putEnumSetInt(int index, Set set) { - buf.putEnumSetInt(index, set); - return this; - } - - @Override - public > IoBuffer putEnumSetLong(Set set) { - buf.putEnumSetLong(set); - return this; - } - - @Override - public > IoBuffer putEnumSetLong(int index, Set set) { - buf.putEnumSetLong(index, set); - return this; - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF 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 com.google.code.yanf4j.buffer; + +import java.io.FilterOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.CharBuffer; +import java.nio.DoubleBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.nio.LongBuffer; +import java.nio.ShortBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; +import java.util.EnumSet; +import java.util.Set; + +/** + * A {@link IoBuffer} that wraps a buffer and proxies any operations to it. + *

+ * You can think this class like a {@link FilterOutputStream}. All operations are proxied by default + * so that you can extend this class and override existing operations selectively. You can introduce + * new operations, too. + * + * @author The Apache MINA Project (dev@mina.apache.org) + * @version $Rev: 671827 $, $Date: 2008-06-26 10:49:48 +0200 (Thu, 26 Jun 2008) $ + */ +public class IoBufferWrapper extends IoBuffer { + + /** + * The buffer proxied by this proxy. + */ + private final IoBuffer buf; + + /** + * Create a new instance. + * + * @param buf the buffer to be proxied + */ + protected IoBufferWrapper(IoBuffer buf) { + if (buf == null) { + throw new NullPointerException("buf"); + } + this.buf = buf; + } + + /** + * Returns the parent buffer that this buffer wrapped. + */ + public IoBuffer getParentBuffer() { + return buf; + } + + @Override + public boolean isDirect() { + return buf.isDirect(); + } + + @Override + public ByteBuffer buf() { + return buf.buf(); + } + + @Override + public int capacity() { + return buf.capacity(); + } + + @Override + public int position() { + return buf.position(); + } + + @Override + public IoBuffer position(int newPosition) { + buf.position(newPosition); + return this; + } + + @Override + public int limit() { + return buf.limit(); + } + + @Override + public IoBuffer limit(int newLimit) { + buf.limit(newLimit); + return this; + } + + @Override + public IoBuffer mark() { + buf.mark(); + return this; + } + + @Override + public IoBuffer reset() { + buf.reset(); + return this; + } + + @Override + public IoBuffer clear() { + buf.clear(); + return this; + } + + @Override + public IoBuffer sweep() { + buf.sweep(); + return this; + } + + @Override + public IoBuffer sweep(byte value) { + buf.sweep(value); + return this; + } + + @Override + public IoBuffer flip() { + buf.flip(); + return this; + } + + @Override + public IoBuffer rewind() { + buf.rewind(); + return this; + } + + @Override + public int remaining() { + return buf.remaining(); + } + + @Override + public boolean hasRemaining() { + return buf.hasRemaining(); + } + + @Override + public byte get() { + return buf.get(); + } + + @Override + public short getUnsigned() { + return buf.getUnsigned(); + } + + @Override + public IoBuffer put(byte b) { + buf.put(b); + return this; + } + + @Override + public byte get(int index) { + return buf.get(index); + } + + @Override + public short getUnsigned(int index) { + return buf.getUnsigned(index); + } + + @Override + public IoBuffer put(int index, byte b) { + buf.put(index, b); + return this; + } + + @Override + public IoBuffer get(byte[] dst, int offset, int length) { + buf.get(dst, offset, length); + return this; + } + + @Override + public IoBuffer getSlice(int index, int length) { + return buf.getSlice(index, length); + } + + @Override + public IoBuffer getSlice(int length) { + return buf.getSlice(length); + } + + @Override + public IoBuffer get(byte[] dst) { + buf.get(dst); + return this; + } + + @Override + public IoBuffer put(IoBuffer src) { + buf.put(src); + return this; + } + + @Override + public IoBuffer put(ByteBuffer src) { + buf.put(src); + return this; + } + + @Override + public IoBuffer put(byte[] src, int offset, int length) { + buf.put(src, offset, length); + return this; + } + + @Override + public IoBuffer put(byte[] src) { + buf.put(src); + return this; + } + + @Override + public IoBuffer compact() { + buf.compact(); + return this; + } + + @Override + public String toString() { + return buf.toString(); + } + + @Override + public int hashCode() { + return buf.hashCode(); + } + + @Override + public boolean equals(Object ob) { + return buf.equals(ob); + } + + public int compareTo(IoBuffer that) { + return buf.compareTo(that); + } + + @Override + public ByteOrder order() { + return buf.order(); + } + + @Override + public IoBuffer order(ByteOrder bo) { + buf.order(bo); + return this; + } + + @Override + public char getChar() { + return buf.getChar(); + } + + @Override + public IoBuffer putChar(char value) { + buf.putChar(value); + return this; + } + + @Override + public char getChar(int index) { + return buf.getChar(index); + } + + @Override + public IoBuffer putChar(int index, char value) { + buf.putChar(index, value); + return this; + } + + @Override + public CharBuffer asCharBuffer() { + return buf.asCharBuffer(); + } + + @Override + public short getShort() { + return buf.getShort(); + } + + @Override + public int getUnsignedShort() { + return buf.getUnsignedShort(); + } + + @Override + public IoBuffer putShort(short value) { + buf.putShort(value); + return this; + } + + @Override + public short getShort(int index) { + return buf.getShort(index); + } + + @Override + public int getUnsignedShort(int index) { + return buf.getUnsignedShort(index); + } + + @Override + public IoBuffer putShort(int index, short value) { + buf.putShort(index, value); + return this; + } + + @Override + public ShortBuffer asShortBuffer() { + return buf.asShortBuffer(); + } + + @Override + public int getInt() { + return buf.getInt(); + } + + @Override + public long getUnsignedInt() { + return buf.getUnsignedInt(); + } + + @Override + public IoBuffer putInt(int value) { + buf.putInt(value); + return this; + } + + @Override + public int getInt(int index) { + return buf.getInt(index); + } + + @Override + public long getUnsignedInt(int index) { + return buf.getUnsignedInt(index); + } + + @Override + public IoBuffer putInt(int index, int value) { + buf.putInt(index, value); + return this; + } + + @Override + public IntBuffer asIntBuffer() { + return buf.asIntBuffer(); + } + + @Override + public long getLong() { + return buf.getLong(); + } + + @Override + public IoBuffer putLong(long value) { + buf.putLong(value); + return this; + } + + @Override + public long getLong(int index) { + return buf.getLong(index); + } + + @Override + public IoBuffer putLong(int index, long value) { + buf.putLong(index, value); + return this; + } + + @Override + public LongBuffer asLongBuffer() { + return buf.asLongBuffer(); + } + + @Override + public float getFloat() { + return buf.getFloat(); + } + + @Override + public IoBuffer putFloat(float value) { + buf.putFloat(value); + return this; + } + + @Override + public float getFloat(int index) { + return buf.getFloat(index); + } + + @Override + public IoBuffer putFloat(int index, float value) { + buf.putFloat(index, value); + return this; + } + + @Override + public FloatBuffer asFloatBuffer() { + return buf.asFloatBuffer(); + } + + @Override + public double getDouble() { + return buf.getDouble(); + } + + @Override + public IoBuffer putDouble(double value) { + buf.putDouble(value); + return this; + } + + @Override + public double getDouble(int index) { + return buf.getDouble(index); + } + + @Override + public IoBuffer putDouble(int index, double value) { + buf.putDouble(index, value); + return this; + } + + @Override + public DoubleBuffer asDoubleBuffer() { + return buf.asDoubleBuffer(); + } + + @Override + public String getHexDump() { + return buf.getHexDump(); + } + + @Override + public String getString(int fieldSize, CharsetDecoder decoder) throws CharacterCodingException { + return buf.getString(fieldSize, decoder); + } + + @Override + public String getString(CharsetDecoder decoder) throws CharacterCodingException { + return buf.getString(decoder); + } + + @Override + public String getPrefixedString(CharsetDecoder decoder) throws CharacterCodingException { + return buf.getPrefixedString(decoder); + } + + @Override + public String getPrefixedString(int prefixLength, CharsetDecoder decoder) + throws CharacterCodingException { + return buf.getPrefixedString(prefixLength, decoder); + } + + @Override + public IoBuffer putString(CharSequence in, int fieldSize, CharsetEncoder encoder) + throws CharacterCodingException { + buf.putString(in, fieldSize, encoder); + return this; + } + + @Override + public IoBuffer putString(CharSequence in, CharsetEncoder encoder) + throws CharacterCodingException { + buf.putString(in, encoder); + return this; + } + + @Override + public IoBuffer putPrefixedString(CharSequence in, CharsetEncoder encoder) + throws CharacterCodingException { + buf.putPrefixedString(in, encoder); + return this; + } + + @Override + public IoBuffer putPrefixedString(CharSequence in, int prefixLength, CharsetEncoder encoder) + throws CharacterCodingException { + buf.putPrefixedString(in, prefixLength, encoder); + return this; + } + + @Override + public IoBuffer putPrefixedString(CharSequence in, int prefixLength, int padding, + CharsetEncoder encoder) throws CharacterCodingException { + buf.putPrefixedString(in, prefixLength, padding, encoder); + return this; + } + + @Override + public IoBuffer putPrefixedString(CharSequence in, int prefixLength, int padding, byte padValue, + CharsetEncoder encoder) throws CharacterCodingException { + buf.putPrefixedString(in, prefixLength, padding, padValue, encoder); + return this; + } + + @Override + public IoBuffer skip(int size) { + buf.skip(size); + return this; + } + + @Override + public IoBuffer fill(byte value, int size) { + buf.fill(value, size); + return this; + } + + @Override + public IoBuffer fillAndReset(byte value, int size) { + buf.fillAndReset(value, size); + return this; + } + + @Override + public IoBuffer fill(int size) { + buf.fill(size); + return this; + } + + @Override + public IoBuffer fillAndReset(int size) { + buf.fillAndReset(size); + return this; + } + + @Override + public boolean isAutoExpand() { + return buf.isAutoExpand(); + } + + @Override + public IoBuffer setAutoExpand(boolean autoExpand) { + buf.setAutoExpand(autoExpand); + return this; + } + + @Override + public IoBuffer expand(int pos, int expectedRemaining) { + buf.expand(pos, expectedRemaining); + return this; + } + + @Override + public IoBuffer expand(int expectedRemaining) { + buf.expand(expectedRemaining); + return this; + } + + @Override + public Object getObject() throws ClassNotFoundException { + return buf.getObject(); + } + + @Override + public Object getObject(ClassLoader classLoader) throws ClassNotFoundException { + return buf.getObject(classLoader); + } + + @Override + public IoBuffer putObject(Object o) { + buf.putObject(o); + return this; + } + + @Override + public InputStream asInputStream() { + return buf.asInputStream(); + } + + @Override + public OutputStream asOutputStream() { + return buf.asOutputStream(); + } + + @Override + public IoBuffer duplicate() { + return buf.duplicate(); + } + + @Override + public IoBuffer slice() { + return buf.slice(); + } + + @Override + public IoBuffer asReadOnlyBuffer() { + return buf.asReadOnlyBuffer(); + } + + @Override + public byte[] array() { + return buf.array(); + } + + @Override + public int arrayOffset() { + return buf.arrayOffset(); + } + + @Override + public int minimumCapacity() { + return buf.minimumCapacity(); + } + + @Override + public IoBuffer minimumCapacity(int minimumCapacity) { + buf.minimumCapacity(minimumCapacity); + return this; + } + + @Override + public IoBuffer capacity(int newCapacity) { + buf.capacity(newCapacity); + return this; + } + + @Override + public boolean isReadOnly() { + return buf.isReadOnly(); + } + + @Override + public int markValue() { + return buf.markValue(); + } + + @Override + public boolean hasArray() { + return buf.hasArray(); + } + + @Override + public void free() { + buf.free(); + } + + @Override + public boolean isDerived() { + return buf.isDerived(); + } + + @Override + public boolean isAutoShrink() { + return buf.isAutoShrink(); + } + + @Override + public IoBuffer setAutoShrink(boolean autoShrink) { + buf.setAutoShrink(autoShrink); + return this; + } + + @Override + public IoBuffer shrink() { + buf.shrink(); + return this; + } + + @Override + public int getMediumInt() { + return buf.getMediumInt(); + } + + @Override + public int getUnsignedMediumInt() { + return buf.getUnsignedMediumInt(); + } + + @Override + public int getMediumInt(int index) { + return buf.getMediumInt(index); + } + + @Override + public int getUnsignedMediumInt(int index) { + return buf.getUnsignedMediumInt(index); + } + + @Override + public IoBuffer putMediumInt(int value) { + buf.putMediumInt(value); + return this; + } + + @Override + public IoBuffer putMediumInt(int index, int value) { + buf.putMediumInt(index, value); + return this; + } + + @Override + public String getHexDump(int lengthLimit) { + return buf.getHexDump(lengthLimit); + } + + @Override + public boolean prefixedDataAvailable(int prefixLength) { + return buf.prefixedDataAvailable(prefixLength); + } + + @Override + public boolean prefixedDataAvailable(int prefixLength, int maxDataLength) { + return buf.prefixedDataAvailable(prefixLength, maxDataLength); + } + + @Override + public int indexOf(byte b) { + return buf.indexOf(b); + } + + @Override + public > E getEnum(Class enumClass) { + return buf.getEnum(enumClass); + } + + @Override + public > E getEnum(int index, Class enumClass) { + return buf.getEnum(index, enumClass); + } + + @Override + public > E getEnumShort(Class enumClass) { + return buf.getEnumShort(enumClass); + } + + @Override + public > E getEnumShort(int index, Class enumClass) { + return buf.getEnumShort(index, enumClass); + } + + @Override + public > E getEnumInt(Class enumClass) { + return buf.getEnumInt(enumClass); + } + + @Override + public > E getEnumInt(int index, Class enumClass) { + return buf.getEnumInt(index, enumClass); + } + + @Override + public IoBuffer putEnum(Enum e) { + buf.putEnum(e); + return this; + } + + @Override + public IoBuffer putEnum(int index, Enum e) { + buf.putEnum(index, e); + return this; + } + + @Override + public IoBuffer putEnumShort(Enum e) { + buf.putEnumShort(e); + return this; + } + + @Override + public IoBuffer putEnumShort(int index, Enum e) { + buf.putEnumShort(index, e); + return this; + } + + @Override + public IoBuffer putEnumInt(Enum e) { + buf.putEnumInt(e); + return this; + } + + @Override + public IoBuffer putEnumInt(int index, Enum e) { + buf.putEnumInt(index, e); + return this; + } + + @Override + public > EnumSet getEnumSet(Class enumClass) { + return buf.getEnumSet(enumClass); + } + + @Override + public > EnumSet getEnumSet(int index, Class enumClass) { + return buf.getEnumSet(index, enumClass); + } + + @Override + public > EnumSet getEnumSetShort(Class enumClass) { + return buf.getEnumSetShort(enumClass); + } + + @Override + public > EnumSet getEnumSetShort(int index, Class enumClass) { + return buf.getEnumSetShort(index, enumClass); + } + + @Override + public > EnumSet getEnumSetInt(Class enumClass) { + return buf.getEnumSetInt(enumClass); + } + + @Override + public > EnumSet getEnumSetInt(int index, Class enumClass) { + return buf.getEnumSetInt(index, enumClass); + } + + @Override + public > EnumSet getEnumSetLong(Class enumClass) { + return buf.getEnumSetLong(enumClass); + } + + @Override + public > EnumSet getEnumSetLong(int index, Class enumClass) { + return buf.getEnumSetLong(index, enumClass); + } + + @Override + public > IoBuffer putEnumSet(Set set) { + buf.putEnumSet(set); + return this; + } + + @Override + public > IoBuffer putEnumSet(int index, Set set) { + buf.putEnumSet(index, set); + return this; + } + + @Override + public > IoBuffer putEnumSetShort(Set set) { + buf.putEnumSetShort(set); + return this; + } + + @Override + public > IoBuffer putEnumSetShort(int index, Set set) { + buf.putEnumSetShort(index, set); + return this; + } + + @Override + public > IoBuffer putEnumSetInt(Set set) { + buf.putEnumSetInt(set); + return this; + } + + @Override + public > IoBuffer putEnumSetInt(int index, Set set) { + buf.putEnumSetInt(index, set); + return this; + } + + @Override + public > IoBuffer putEnumSetLong(Set set) { + buf.putEnumSetLong(set); + return this; + } + + @Override + public > IoBuffer putEnumSetLong(int index, Set set) { + buf.putEnumSetLong(index, set); + return this; + } +} diff --git a/src/main/java/com/google/code/yanf4j/buffer/SimpleBufferAllocator.java b/src/main/java/com/google/code/yanf4j/buffer/SimpleBufferAllocator.java index 1ef21cc8e..6e5549183 100644 --- a/src/main/java/com/google/code/yanf4j/buffer/SimpleBufferAllocator.java +++ b/src/main/java/com/google/code/yanf4j/buffer/SimpleBufferAllocator.java @@ -1,114 +1,105 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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 com.google.code.yanf4j.buffer; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/** - * A simplistic {@link IoBufferAllocator} which simply allocates a new buffer - * every time. - * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev: 671827 $, $Date: 2008-06-26 10:49:48 +0200 (Thu, 26 Jun 2008) - * $ - */ -public class SimpleBufferAllocator implements IoBufferAllocator { - - public IoBuffer allocate(int capacity, boolean direct) { - return wrap(allocateNioBuffer(capacity, direct)); - } - - public ByteBuffer allocateNioBuffer(int capacity, boolean direct) { - ByteBuffer nioBuffer; - if (direct) { - nioBuffer = ByteBuffer.allocateDirect(capacity); - } else { - nioBuffer = ByteBuffer.allocate(capacity); - } - return nioBuffer; - } - - public IoBuffer wrap(ByteBuffer nioBuffer) { - return new SimpleBuffer(nioBuffer); - } - - public void dispose() { - } - - private class SimpleBuffer extends AbstractIoBuffer { - private ByteBuffer buf; - - protected SimpleBuffer(ByteBuffer buf) { - super(SimpleBufferAllocator.this, buf.capacity()); - this.buf = buf; - buf.order(ByteOrder.BIG_ENDIAN); - } - - protected SimpleBuffer(SimpleBuffer parent, ByteBuffer buf) { - super(parent); - this.buf = buf; - } - - @Override - public ByteBuffer buf() { - return buf; - } - - @Override - protected void buf(ByteBuffer buf) { - this.buf = buf; - } - - @Override - protected IoBuffer duplicate0() { - return new SimpleBuffer(this, this.buf.duplicate()); - } - - @Override - protected IoBuffer slice0() { - return new SimpleBuffer(this, this.buf.slice()); - } - - @Override - protected IoBuffer asReadOnlyBuffer0() { - return new SimpleBuffer(this, this.buf.asReadOnlyBuffer()); - } - - @Override - public byte[] array() { - return buf.array(); - } - - @Override - public int arrayOffset() { - return buf.arrayOffset(); - } - - @Override - public boolean hasArray() { - return buf.hasArray(); - } - - @Override - public void free() { - } - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF 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 com.google.code.yanf4j.buffer; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * A simplistic {@link IoBufferAllocator} which simply allocates a new buffer every time. + * + * @author The Apache MINA Project (dev@mina.apache.org) + * @version $Rev: 671827 $, $Date: 2008-06-26 10:49:48 +0200 (Thu, 26 Jun 2008) $ + */ +public class SimpleBufferAllocator implements IoBufferAllocator { + + public IoBuffer allocate(int capacity, boolean direct) { + return wrap(allocateNioBuffer(capacity, direct)); + } + + public ByteBuffer allocateNioBuffer(int capacity, boolean direct) { + ByteBuffer nioBuffer; + if (direct) { + nioBuffer = ByteBuffer.allocateDirect(capacity); + } else { + nioBuffer = ByteBuffer.allocate(capacity); + } + return nioBuffer; + } + + public IoBuffer wrap(ByteBuffer nioBuffer) { + return new SimpleBuffer(nioBuffer); + } + + public void dispose() {} + + private class SimpleBuffer extends AbstractIoBuffer { + private ByteBuffer buf; + + protected SimpleBuffer(ByteBuffer buf) { + super(SimpleBufferAllocator.this, buf.capacity()); + this.buf = buf; + buf.order(ByteOrder.BIG_ENDIAN); + } + + protected SimpleBuffer(SimpleBuffer parent, ByteBuffer buf) { + super(parent); + this.buf = buf; + } + + @Override + public ByteBuffer buf() { + return buf; + } + + @Override + protected void buf(ByteBuffer buf) { + this.buf = buf; + } + + @Override + protected IoBuffer duplicate0() { + return new SimpleBuffer(this, this.buf.duplicate()); + } + + @Override + protected IoBuffer slice0() { + return new SimpleBuffer(this, this.buf.slice()); + } + + @Override + protected IoBuffer asReadOnlyBuffer0() { + return new SimpleBuffer(this, this.buf.asReadOnlyBuffer()); + } + + @Override + public byte[] array() { + return buf.array(); + } + + @Override + public int arrayOffset() { + return buf.arrayOffset(); + } + + @Override + public boolean hasArray() { + return buf.hasArray(); + } + + @Override + public void free() {} + } +} diff --git a/src/main/java/com/google/code/yanf4j/buffer/package.html b/src/main/java/com/google/code/yanf4j/buffer/package.html index f5b8d3e33..e337cf1dd 100644 --- a/src/main/java/com/google/code/yanf4j/buffer/package.html +++ b/src/main/java/com/google/code/yanf4j/buffer/package.html @@ -1,14 +1,10 @@ - - + - -IoBuffer - - - -

IoBuffer from mina

- - - + + IoBuffer + + +

IoBuffer from mina

+ + \ No newline at end of file diff --git a/src/main/java/com/google/code/yanf4j/config/Configuration.java b/src/main/java/com/google/code/yanf4j/config/Configuration.java index 8eced9bd1..36134d3ae 100644 --- a/src/main/java/com/google/code/yanf4j/config/Configuration.java +++ b/src/main/java/com/google/code/yanf4j/config/Configuration.java @@ -1,20 +1,15 @@ /** - *Copyright [2009-2010] [dennis zhuang] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang] Licensed 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 com.google.code.yanf4j.config; import net.rubyeye.xmemcached.impl.ReconnectRequest; - import java.util.concurrent.DelayQueue; - import com.google.code.yanf4j.util.SystemUtils; /** @@ -25,177 +20,172 @@ */ public class Configuration { - public static final String XMEMCACHED_SELECTOR_POOL_SIZE = "xmemcached.selector.pool.size"; - - /** - * Read buffer size per connection - */ - private int sessionReadBufferSize = 32 * 1024; - - /** - * Socket SO_TIMEOUT option - */ - private int soTimeout = 0; - - /** - * Thread count for processing WRITABLE event - */ - private int writeThreadCount = 0; - - /** - * Whether to enable statistics - */ - private boolean statisticsServer = false; - - /** - * Whether to handle read write concurrently,default is true - */ - private boolean handleReadWriteConcurrently = true; - - /** - * Thread coount for processing message dispatching - */ - private int dispatchMessageThreadCount = 0; - - /** - * THread count for processing READABLE event - */ - private int readThreadCount = 1; - - private int selectorPoolSize = System - .getProperty(XMEMCACHED_SELECTOR_POOL_SIZE) == null - ? SystemUtils.getSystemThreadCount() - : Integer.parseInt( - System.getProperty(XMEMCACHED_SELECTOR_POOL_SIZE)); - - /** - * Increasing buffer size per time - */ - public static final int DEFAULT_INCREASE_BUFF_SIZE = 32 * 1024; - - /** - * Max read buffer size for connection - */ - public final static int MAX_READ_BUFFER_SIZE = 128 * 1024; - - /** - * check session idle interval - */ - private long checkSessionTimeoutInterval = 1000L; - - public final int getWriteThreadCount() { - return this.writeThreadCount; - } - - public final int getDispatchMessageThreadCount() { - return this.dispatchMessageThreadCount; - } - - public final void setDispatchMessageThreadCount( - int dispatchMessageThreadCount) { - this.dispatchMessageThreadCount = dispatchMessageThreadCount; - } - - public final void setWriteThreadCount(int writeThreadCount) { - this.writeThreadCount = writeThreadCount; - } - - private long sessionIdleTimeout = 5000L; - - /** - * @see setSessionIdleTimeout - * @return - */ - public final long getSessionIdleTimeout() { - return this.sessionIdleTimeout; - } - - public final void setSessionIdleTimeout(long sessionIdleTimeout) { - this.sessionIdleTimeout = sessionIdleTimeout; - } - - /** - * @see setSessionReadBufferSize - * @return - */ - public final int getSessionReadBufferSize() { - return this.sessionReadBufferSize; - } - - public final boolean isHandleReadWriteConcurrently() { - return this.handleReadWriteConcurrently; - } - - public final int getSoTimeout() { - return this.soTimeout; - } - - protected long statisticsInterval = 5 * 60 * 1000L; - - public final long getStatisticsInterval() { - return this.statisticsInterval; - } - - public final void setStatisticsInterval(long statisticsInterval) { - this.statisticsInterval = statisticsInterval; - } - - public final void setSoTimeout(int soTimeout) { - if (soTimeout < 0) { - throw new IllegalArgumentException("soTimeout<0"); - } - this.soTimeout = soTimeout; - } - - public final void setHandleReadWriteConcurrently( - boolean handleReadWriteConcurrently) { - this.handleReadWriteConcurrently = handleReadWriteConcurrently; - } - - public final void setSessionReadBufferSize(int tcpHandlerReadBufferSize) { - if (tcpHandlerReadBufferSize <= 0) { - throw new IllegalArgumentException("tcpHandlerReadBufferSize<=0"); - } - this.sessionReadBufferSize = tcpHandlerReadBufferSize; - } - - public final boolean isStatisticsServer() { - return this.statisticsServer; - } - - public final void setStatisticsServer(boolean statisticsServer) { - this.statisticsServer = statisticsServer; - } - - /** - * @see setReadThreadCount - * @return - */ - public final int getReadThreadCount() { - return this.readThreadCount; - } - - public final void setReadThreadCount(int readThreadCount) { - if (readThreadCount < 0) { - throw new IllegalArgumentException("readThreadCount<0"); - } - this.readThreadCount = readThreadCount; - } - - public void setCheckSessionTimeoutInterval( - long checkSessionTimeoutInterval) { - this.checkSessionTimeoutInterval = checkSessionTimeoutInterval; - } - - public long getCheckSessionTimeoutInterval() { - return this.checkSessionTimeoutInterval; - } - - public void setSelectorPoolSize(int selectorPoolSize) { - this.selectorPoolSize = selectorPoolSize; - } - - public int getSelectorPoolSize() { - return selectorPoolSize; - } + public static final String XMEMCACHED_SELECTOR_POOL_SIZE = "xmemcached.selector.pool.size"; + + /** + * Read buffer size per connection + */ + private int sessionReadBufferSize = 32 * 1024; + + /** + * Socket SO_TIMEOUT option + */ + private int soTimeout = 0; + + /** + * Thread count for processing WRITABLE event + */ + private int writeThreadCount = 0; + + /** + * Whether to enable statistics + */ + private boolean statisticsServer = false; + + /** + * Whether to handle read write concurrently,default is true + */ + private boolean handleReadWriteConcurrently = true; + + /** + * Thread coount for processing message dispatching + */ + private int dispatchMessageThreadCount = 0; + + /** + * THread count for processing READABLE event + */ + private int readThreadCount = 1; + + private int selectorPoolSize = + System.getProperty(XMEMCACHED_SELECTOR_POOL_SIZE) == null ? SystemUtils.getSystemThreadCount() + : Integer.parseInt(System.getProperty(XMEMCACHED_SELECTOR_POOL_SIZE)); + + /** + * Increasing buffer size per time + */ + public static final int DEFAULT_INCREASE_BUFF_SIZE = 32 * 1024; + + /** + * Max read buffer size for connection + */ + public final static int MAX_READ_BUFFER_SIZE = 128 * 1024; + + /** + * check session idle interval + */ + private long checkSessionTimeoutInterval = 1000L; + + public final int getWriteThreadCount() { + return this.writeThreadCount; + } + + public final int getDispatchMessageThreadCount() { + return this.dispatchMessageThreadCount; + } + + public final void setDispatchMessageThreadCount(int dispatchMessageThreadCount) { + this.dispatchMessageThreadCount = dispatchMessageThreadCount; + } + + public final void setWriteThreadCount(int writeThreadCount) { + this.writeThreadCount = writeThreadCount; + } + + private long sessionIdleTimeout = 5000L; + + /** + * @see setSessionIdleTimeout + * @return + */ + public final long getSessionIdleTimeout() { + return this.sessionIdleTimeout; + } + + public final void setSessionIdleTimeout(long sessionIdleTimeout) { + this.sessionIdleTimeout = sessionIdleTimeout; + } + + /** + * @see setSessionReadBufferSize + * @return + */ + public final int getSessionReadBufferSize() { + return this.sessionReadBufferSize; + } + + public final boolean isHandleReadWriteConcurrently() { + return this.handleReadWriteConcurrently; + } + + public final int getSoTimeout() { + return this.soTimeout; + } + + protected long statisticsInterval = 5 * 60 * 1000L; + + public final long getStatisticsInterval() { + return this.statisticsInterval; + } + + public final void setStatisticsInterval(long statisticsInterval) { + this.statisticsInterval = statisticsInterval; + } + + public final void setSoTimeout(int soTimeout) { + if (soTimeout < 0) { + throw new IllegalArgumentException("soTimeout<0"); + } + this.soTimeout = soTimeout; + } + + public final void setHandleReadWriteConcurrently(boolean handleReadWriteConcurrently) { + this.handleReadWriteConcurrently = handleReadWriteConcurrently; + } + + public final void setSessionReadBufferSize(int tcpHandlerReadBufferSize) { + if (tcpHandlerReadBufferSize <= 0) { + throw new IllegalArgumentException("tcpHandlerReadBufferSize<=0"); + } + this.sessionReadBufferSize = tcpHandlerReadBufferSize; + } + + public final boolean isStatisticsServer() { + return this.statisticsServer; + } + + public final void setStatisticsServer(boolean statisticsServer) { + this.statisticsServer = statisticsServer; + } + + /** + * @see setReadThreadCount + * @return + */ + public final int getReadThreadCount() { + return this.readThreadCount; + } + + public final void setReadThreadCount(int readThreadCount) { + if (readThreadCount < 0) { + throw new IllegalArgumentException("readThreadCount<0"); + } + this.readThreadCount = readThreadCount; + } + + public void setCheckSessionTimeoutInterval(long checkSessionTimeoutInterval) { + this.checkSessionTimeoutInterval = checkSessionTimeoutInterval; + } + + public long getCheckSessionTimeoutInterval() { + return this.checkSessionTimeoutInterval; + } + + public void setSelectorPoolSize(int selectorPoolSize) { + this.selectorPoolSize = selectorPoolSize; + } + + public int getSelectorPoolSize() { + return selectorPoolSize; + } } diff --git a/src/main/java/com/google/code/yanf4j/config/package.html b/src/main/java/com/google/code/yanf4j/config/package.html index b82502bf5..aa75bc58f 100644 --- a/src/main/java/com/google/code/yanf4j/config/package.html +++ b/src/main/java/com/google/code/yanf4j/config/package.html @@ -1,14 +1,10 @@ - - + - -Networking configuration - - - -

Networking configuration

- - - + + Networking configuration + + +

Networking configuration

+ + \ No newline at end of file diff --git a/src/main/java/com/google/code/yanf4j/core/CodecFactory.java b/src/main/java/com/google/code/yanf4j/core/CodecFactory.java index 0cb6c3f32..f0cdb0411 100644 --- a/src/main/java/com/google/code/yanf4j/core/CodecFactory.java +++ b/src/main/java/com/google/code/yanf4j/core/CodecFactory.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.core; @@ -34,15 +28,15 @@ */ public interface CodecFactory { - public interface Encoder { - public IoBuffer encode(Object message, Session session); - } + public interface Encoder { + public IoBuffer encode(Object message, Session session); + } - public interface Decoder { - public Object decode(IoBuffer buff, Session session); - } + public interface Decoder { + public Object decode(IoBuffer buff, Session session); + } - public Encoder getEncoder(); + public Encoder getEncoder(); - public Decoder getDecoder(); + public Decoder getDecoder(); } diff --git a/src/main/java/com/google/code/yanf4j/core/Controller.java b/src/main/java/com/google/code/yanf4j/core/Controller.java index 075b8a037..0c3d0b0c3 100644 --- a/src/main/java/com/google/code/yanf4j/core/Controller.java +++ b/src/main/java/com/google/code/yanf4j/core/Controller.java @@ -1,30 +1,23 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.core; import java.io.IOException; import java.net.InetSocketAddress; - import com.google.code.yanf4j.statistics.Statistics; /** @@ -36,70 +29,68 @@ */ public interface Controller { - public abstract long getSessionTimeout(); + public abstract long getSessionTimeout(); - public long getSessionIdleTimeout(); + public long getSessionIdleTimeout(); - public void setSessionIdleTimeout(long sessionIdleTimeout); + public void setSessionIdleTimeout(long sessionIdleTimeout); - public abstract void setSessionTimeout(long sessionTimeout); + public abstract void setSessionTimeout(long sessionTimeout); - public abstract int getSoTimeout(); + public abstract int getSoTimeout(); - public abstract void setSoTimeout(int timeout); + public abstract void setSoTimeout(int timeout); - public abstract void addStateListener(ControllerStateListener listener); + public abstract void addStateListener(ControllerStateListener listener); - public void removeStateListener(ControllerStateListener listener); + public void removeStateListener(ControllerStateListener listener); - public abstract boolean isHandleReadWriteConcurrently(); + public abstract boolean isHandleReadWriteConcurrently(); - public abstract void setHandleReadWriteConcurrently( - boolean handleReadWriteConcurrently); + public abstract void setHandleReadWriteConcurrently(boolean handleReadWriteConcurrently); - public abstract int getReadThreadCount(); + public abstract int getReadThreadCount(); - public abstract void setReadThreadCount(int readThreadCount); + public abstract void setReadThreadCount(int readThreadCount); - public abstract Handler getHandler(); + public abstract Handler getHandler(); - public abstract void setHandler(Handler handler); + public abstract void setHandler(Handler handler); - public abstract int getPort(); + public abstract int getPort(); - public abstract void start() throws IOException; + public abstract void start() throws IOException; - public abstract boolean isStarted(); + public abstract boolean isStarted(); - public abstract Statistics getStatistics(); + public abstract Statistics getStatistics(); - public abstract CodecFactory getCodecFactory(); + public abstract CodecFactory getCodecFactory(); - public abstract void setCodecFactory(CodecFactory codecFactory); + public abstract void setCodecFactory(CodecFactory codecFactory); - public abstract void stop() throws IOException; + public abstract void stop() throws IOException; - public void setReceiveThroughputLimit(double receivePacketRate); + public void setReceiveThroughputLimit(double receivePacketRate); - public double getReceiveThroughputLimit(); + public double getReceiveThroughputLimit(); - public double getSendThroughputLimit(); + public double getSendThroughputLimit(); - public void setSendThroughputLimit(double sendThroughputLimit); + public void setSendThroughputLimit(double sendThroughputLimit); - public InetSocketAddress getLocalSocketAddress(); + public InetSocketAddress getLocalSocketAddress(); - public void setLocalSocketAddress(InetSocketAddress inetAddress); + public void setLocalSocketAddress(InetSocketAddress inetAddress); - public int getDispatchMessageThreadCount(); + public int getDispatchMessageThreadCount(); - public void setDispatchMessageThreadCount( - int dispatchMessageThreadPoolSize); + public void setDispatchMessageThreadCount(int dispatchMessageThreadPoolSize); - public int getWriteThreadCount(); + public int getWriteThreadCount(); - public void setWriteThreadCount(int writeThreadCount); + public void setWriteThreadCount(int writeThreadCount); - public void setSocketOption(SocketOption socketOption, T value); + public void setSocketOption(SocketOption socketOption, T value); -} \ No newline at end of file +} diff --git a/src/main/java/com/google/code/yanf4j/core/ControllerLifeCycle.java b/src/main/java/com/google/code/yanf4j/core/ControllerLifeCycle.java index 1a67d328d..5afbf4d9d 100644 --- a/src/main/java/com/google/code/yanf4j/core/ControllerLifeCycle.java +++ b/src/main/java/com/google/code/yanf4j/core/ControllerLifeCycle.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.core; @@ -31,13 +25,13 @@ public interface ControllerLifeCycle { - public void notifyReady(); + public void notifyReady(); - public void notifyStarted(); + public void notifyStarted(); - public void notifyAllSessionClosed(); + public void notifyAllSessionClosed(); - public void notifyException(Throwable t); + public void notifyException(Throwable t); - public void notifyStopped(); + public void notifyStopped(); } diff --git a/src/main/java/com/google/code/yanf4j/core/ControllerStateListener.java b/src/main/java/com/google/code/yanf4j/core/ControllerStateListener.java index dbba54f60..688b1922e 100644 --- a/src/main/java/com/google/code/yanf4j/core/ControllerStateListener.java +++ b/src/main/java/com/google/code/yanf4j/core/ControllerStateListener.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.core; @@ -32,33 +26,33 @@ */ public interface ControllerStateListener { - /** - * When controller is started - * - * @param controller - */ - public void onStarted(final Controller controller); + /** + * When controller is started + * + * @param controller + */ + public void onStarted(final Controller controller); - /** - * When controller is ready - * - * @param controller - */ - public void onReady(final Controller controller); + /** + * When controller is ready + * + * @param controller + */ + public void onReady(final Controller controller); - /** - * When all connections are closed - * - * @param controller - */ - public void onAllSessionClosed(final Controller controller); + /** + * When all connections are closed + * + * @param controller + */ + public void onAllSessionClosed(final Controller controller); - /** - * When controller has been stopped - * - * @param controller - */ - public void onStopped(final Controller controller); + /** + * When controller has been stopped + * + * @param controller + */ + public void onStopped(final Controller controller); - public void onException(final Controller controller, Throwable t); + public void onException(final Controller controller, Throwable t); } diff --git a/src/main/java/com/google/code/yanf4j/core/Dispatcher.java b/src/main/java/com/google/code/yanf4j/core/Dispatcher.java index 3ec383df6..6a2fde444 100644 --- a/src/main/java/com/google/code/yanf4j/core/Dispatcher.java +++ b/src/main/java/com/google/code/yanf4j/core/Dispatcher.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.core; @@ -29,7 +23,7 @@ * */ public interface Dispatcher { - public void dispatch(Runnable r); + public void dispatch(Runnable r); - public void stop(); + public void stop(); } diff --git a/src/main/java/com/google/code/yanf4j/core/EventType.java b/src/main/java/com/google/code/yanf4j/core/EventType.java index 45baf2288..706529cbc 100644 --- a/src/main/java/com/google/code/yanf4j/core/EventType.java +++ b/src/main/java/com/google/code/yanf4j/core/EventType.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.core; @@ -29,5 +23,5 @@ * */ public enum EventType { - REGISTER, READABLE, WRITEABLE, ENABLE_READ, ENABLE_WRITE, UNREGISTER, EXPIRED, IDLE, CONNECTED + REGISTER, READABLE, WRITEABLE, ENABLE_READ, ENABLE_WRITE, UNREGISTER, EXPIRED, IDLE, CONNECTED } diff --git a/src/main/java/com/google/code/yanf4j/core/Handler.java b/src/main/java/com/google/code/yanf4j/core/Handler.java index 24c9a451b..4d29166c2 100644 --- a/src/main/java/com/google/code/yanf4j/core/Handler.java +++ b/src/main/java/com/google/code/yanf4j/core/Handler.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.core; @@ -31,22 +25,22 @@ */ public interface Handler { - public void onSessionCreated(Session session); + public void onSessionCreated(Session session); - public void onSessionStarted(Session session); + public void onSessionStarted(Session session); - public void onSessionClosed(Session session); + public void onSessionClosed(Session session); - public void onMessageReceived(Session session, Object msg); + public void onMessageReceived(Session session, Object msg); - public void onMessageSent(Session session, Object msg); + public void onMessageSent(Session session, Object msg); - public void onExceptionCaught(Session session, Throwable throwable); + public void onExceptionCaught(Session session, Throwable throwable); - public void onSessionExpired(Session session); + public void onSessionExpired(Session session); - public void onSessionIdle(Session session); + public void onSessionIdle(Session session); - public void onSessionConnected(Session session); + public void onSessionConnected(Session session); } diff --git a/src/main/java/com/google/code/yanf4j/core/Session.java b/src/main/java/com/google/code/yanf4j/core/Session.java index 6e7c8170e..c04d02b20 100644 --- a/src/main/java/com/google/code/yanf4j/core/Session.java +++ b/src/main/java/com/google/code/yanf4j/core/Session.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.core; @@ -34,192 +28,189 @@ */ public interface Session { - public enum SessionStatus { - NULL, READING, WRITING, IDLE, INITIALIZE, CLOSING, CLOSED - } - - /** - * Start session - */ - public void start(); - - /** - * Write a message,if you don't care when the message is written - * - * @param packet - */ - public void write(Object packet); - - /** - * Check if session is closed - * - * @return - */ - public boolean isClosed(); - - /** - * Close session - */ - public void close(); - - /** - * Return the remote end's InetSocketAddress - * - * @return - */ - public InetSocketAddress getRemoteSocketAddress(); - - public InetAddress getLocalAddress(); - - /** - * Return true if using blocking write - * - * @return - */ - public boolean isUseBlockingWrite(); - - /** - * Set if using blocking write - * - * @param useBlockingWrite - */ - public void setUseBlockingWrite(boolean useBlockingWrite); - - /** - * Return true if using blocking read - * - * @return - */ - public boolean isUseBlockingRead(); - - public void setUseBlockingRead(boolean useBlockingRead); - - /** - * Flush the write queue,this method may be no effect if OP_WRITE is - * running. - */ - public void flush(); - - /** - * Return true if session is expired,session is expired beacause you set the - * sessionTimeout,if since session's last operation form now is over this - * vlaue,isExpired return true,and Handler.onExpired() will be invoked. - * - * @return - */ - public boolean isExpired(); - - /** - * Check if session is idle - * - * @return - */ - public boolean isIdle(); - - /** - * Return current encoder - * - * @return - */ - public CodecFactory.Encoder getEncoder(); - - /** - * Set encoder - * - * @param encoder - */ - public void setEncoder(CodecFactory.Encoder encoder); - - /** - * Return current decoder - * - * @return - */ - - public CodecFactory.Decoder getDecoder(); - - public void setDecoder(CodecFactory.Decoder decoder); - - /** - * Return true if allow handling read and write concurrently,default is - * true. - * - * @return - */ - public boolean isHandleReadWriteConcurrently(); - - public void setHandleReadWriteConcurrently( - boolean handleReadWriteConcurrently); - - /** - * Return the session read buffer's byte order,big end or little end. - * - * @return - */ - public ByteOrder getReadBufferByteOrder(); - - public void setReadBufferByteOrder(ByteOrder readBufferByteOrder); - - /** - * Set a attribute attched with this session - * - * @param key - * @param value - */ - public void setAttribute(String key, Object value); - - /** - * Remove attribute - * - * @param key - */ - public void removeAttribute(String key); - - /** - * Return attribute associated with key - * - * @param key - * @return - */ - public Object getAttribute(String key); - - /** - * Clear attributes - */ - public void clearAttributes(); - - /** - * Return the bytes in write queue,there bytes is in memory.Use this method - * to controll writing speed. - * - * @return - */ - public long getScheduleWritenBytes(); - - /** - * Return last operation timestamp,operation include read,write,idle - * - * @return - */ - public long getLastOperationTimeStamp(); - - /** - * return true if it is a loopback connection - * - * @return - */ - public boolean isLoopbackConnection(); - - public long getSessionIdleTimeout(); - - public void setSessionIdleTimeout(long sessionIdleTimeout); - - public long getSessionTimeout(); - - public void setSessionTimeout(long sessionTimeout); - - public Object setAttributeIfAbsent(String key, Object value); - - public Handler getHandler(); - -} \ No newline at end of file + public enum SessionStatus { + NULL, READING, WRITING, IDLE, INITIALIZE, CLOSING, CLOSED + } + + /** + * Start session + */ + public void start(); + + /** + * Write a message,if you don't care when the message is written + * + * @param packet + */ + public void write(Object packet); + + /** + * Check if session is closed + * + * @return + */ + public boolean isClosed(); + + /** + * Close session + */ + public void close(); + + /** + * Return the remote end's InetSocketAddress + * + * @return + */ + public InetSocketAddress getRemoteSocketAddress(); + + public InetAddress getLocalAddress(); + + /** + * Return true if using blocking write + * + * @return + */ + public boolean isUseBlockingWrite(); + + /** + * Set if using blocking write + * + * @param useBlockingWrite + */ + public void setUseBlockingWrite(boolean useBlockingWrite); + + /** + * Return true if using blocking read + * + * @return + */ + public boolean isUseBlockingRead(); + + public void setUseBlockingRead(boolean useBlockingRead); + + /** + * Flush the write queue,this method may be no effect if OP_WRITE is running. + */ + public void flush(); + + /** + * Return true if session is expired,session is expired beacause you set the sessionTimeout,if + * since session's last operation form now is over this vlaue,isExpired return true,and + * Handler.onExpired() will be invoked. + * + * @return + */ + public boolean isExpired(); + + /** + * Check if session is idle + * + * @return + */ + public boolean isIdle(); + + /** + * Return current encoder + * + * @return + */ + public CodecFactory.Encoder getEncoder(); + + /** + * Set encoder + * + * @param encoder + */ + public void setEncoder(CodecFactory.Encoder encoder); + + /** + * Return current decoder + * + * @return + */ + + public CodecFactory.Decoder getDecoder(); + + public void setDecoder(CodecFactory.Decoder decoder); + + /** + * Return true if allow handling read and write concurrently,default is true. + * + * @return + */ + public boolean isHandleReadWriteConcurrently(); + + public void setHandleReadWriteConcurrently(boolean handleReadWriteConcurrently); + + /** + * Return the session read buffer's byte order,big end or little end. + * + * @return + */ + public ByteOrder getReadBufferByteOrder(); + + public void setReadBufferByteOrder(ByteOrder readBufferByteOrder); + + /** + * Set a attribute attched with this session + * + * @param key + * @param value + */ + public void setAttribute(String key, Object value); + + /** + * Remove attribute + * + * @param key + */ + public void removeAttribute(String key); + + /** + * Return attribute associated with key + * + * @param key + * @return + */ + public Object getAttribute(String key); + + /** + * Clear attributes + */ + public void clearAttributes(); + + /** + * Return the bytes in write queue,there bytes is in memory.Use this method to controll writing + * speed. + * + * @return + */ + public long getScheduleWritenBytes(); + + /** + * Return last operation timestamp,operation include read,write,idle + * + * @return + */ + public long getLastOperationTimeStamp(); + + /** + * return true if it is a loopback connection + * + * @return + */ + public boolean isLoopbackConnection(); + + public long getSessionIdleTimeout(); + + public void setSessionIdleTimeout(long sessionIdleTimeout); + + public long getSessionTimeout(); + + public void setSessionTimeout(long sessionTimeout); + + public Object setAttributeIfAbsent(String key, Object value); + + public Handler getHandler(); + +} diff --git a/src/main/java/com/google/code/yanf4j/core/SessionConfig.java b/src/main/java/com/google/code/yanf4j/core/SessionConfig.java index 70340635c..55a7ee5a3 100644 --- a/src/main/java/com/google/code/yanf4j/core/SessionConfig.java +++ b/src/main/java/com/google/code/yanf4j/core/SessionConfig.java @@ -1,60 +1,51 @@ -/** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 - */ -/** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 com.google.code.yanf4j.core; - -import java.util.Queue; - -import com.google.code.yanf4j.statistics.Statistics; - -/** - * Session configuration - * - * @author dennis - * - */ -public class SessionConfig { - public final Handler handler; - public final CodecFactory codecFactory; - public final Statistics statistics; - public final Queue queue; - public final Dispatcher dispatchMessageDispatcher; - public final boolean handleReadWriteConcurrently; - public final long sessionTimeout; - public final long sessionIdelTimeout; - - public SessionConfig(Handler handler, CodecFactory codecFactory, - Statistics statistics, Queue queue, - Dispatcher dispatchMessageDispatcher, - boolean handleReadWriteConcurrently, long sessionTimeout, - long sessionIdelTimeout) { - - this.handler = handler; - this.codecFactory = codecFactory; - this.statistics = statistics; - this.queue = queue; - this.dispatchMessageDispatcher = dispatchMessageDispatcher; - this.handleReadWriteConcurrently = handleReadWriteConcurrently; - this.sessionTimeout = sessionTimeout; - this.sessionIdelTimeout = sessionIdelTimeout; - } -} +/** + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 + */ +/** + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.core; + +import java.util.Queue; +import com.google.code.yanf4j.statistics.Statistics; + +/** + * Session configuration + * + * @author dennis + * + */ +public class SessionConfig { + public final Handler handler; + public final CodecFactory codecFactory; + public final Statistics statistics; + public final Queue queue; + public final Dispatcher dispatchMessageDispatcher; + public final boolean handleReadWriteConcurrently; + public final long sessionTimeout; + public final long sessionIdelTimeout; + + public SessionConfig(Handler handler, CodecFactory codecFactory, Statistics statistics, + Queue queue, Dispatcher dispatchMessageDispatcher, + boolean handleReadWriteConcurrently, long sessionTimeout, long sessionIdelTimeout) { + + this.handler = handler; + this.codecFactory = codecFactory; + this.statistics = statistics; + this.queue = queue; + this.dispatchMessageDispatcher = dispatchMessageDispatcher; + this.handleReadWriteConcurrently = handleReadWriteConcurrently; + this.sessionTimeout = sessionTimeout; + this.sessionIdelTimeout = sessionIdelTimeout; + } +} diff --git a/src/main/java/com/google/code/yanf4j/core/SessionManager.java b/src/main/java/com/google/code/yanf4j/core/SessionManager.java index 16d381a67..8bf2c1cf7 100644 --- a/src/main/java/com/google/code/yanf4j/core/SessionManager.java +++ b/src/main/java/com/google/code/yanf4j/core/SessionManager.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.core; @@ -29,17 +23,17 @@ * */ public interface SessionManager { - /** - * Register session to controller - * - * @param session - */ - public void registerSession(Session session); + /** + * Register session to controller + * + * @param session + */ + public void registerSession(Session session); - /** - * Unregister session - * - * @param session - */ - public void unregisterSession(Session session); + /** + * Unregister session + * + * @param session + */ + public void unregisterSession(Session session); } diff --git a/src/main/java/com/google/code/yanf4j/core/SocketOption.java b/src/main/java/com/google/code/yanf4j/core/SocketOption.java index 1d9d40bd1..31a9f949b 100644 --- a/src/main/java/com/google/code/yanf4j/core/SocketOption.java +++ b/src/main/java/com/google/code/yanf4j/core/SocketOption.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.core; @@ -31,56 +25,55 @@ */ public class SocketOption { - private final String name; - private final Class type; + private final String name; + private final Class type; - public SocketOption(String name, Class type) { - this.name = name; - this.type = type; - } + public SocketOption(String name, Class type) { + this.name = name; + this.type = type; + } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result - + (this.name == null ? 0 : this.name.hashCode()); - return result; - } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (this.name == null ? 0 : this.name.hashCode()); + return result; + } - @Override - @SuppressWarnings("unchecked") - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - SocketOption other = (SocketOption) obj; - if (this.name == null) { - if (other.name != null) { - return false; - } - } else if (!this.name.equals(other.name)) { - return false; - } - return true; - } + @Override + @SuppressWarnings("unchecked") + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + SocketOption other = (SocketOption) obj; + if (this.name == null) { + if (other.name != null) { + return false; + } + } else if (!this.name.equals(other.name)) { + return false; + } + return true; + } - public String name() { - return this.name; - } + public String name() { + return this.name; + } - public Class type() { - return this.type; - } + public Class type() { + return this.type; + } - @Override - public String toString() { - return this.name; - } + @Override + public String toString() { + return this.name; + } } diff --git a/src/main/java/com/google/code/yanf4j/core/WriteMessage.java b/src/main/java/com/google/code/yanf4j/core/WriteMessage.java index 12a0443f4..a05c4830f 100644 --- a/src/main/java/com/google/code/yanf4j/core/WriteMessage.java +++ b/src/main/java/com/google/code/yanf4j/core/WriteMessage.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.core; @@ -33,16 +27,16 @@ */ public interface WriteMessage { - public void writing(); + public void writing(); - public boolean isWriting(); + public boolean isWriting(); - public IoBuffer getWriteBuffer(); + public IoBuffer getWriteBuffer(); - public Object getMessage(); + public Object getMessage(); - public void setWriteBuffer(IoBuffer buffers); + public void setWriteBuffer(IoBuffer buffers); - public FutureImpl getWriteFuture(); + public FutureImpl getWriteFuture(); -} \ No newline at end of file +} diff --git a/src/main/java/com/google/code/yanf4j/core/impl/AbstractController.java b/src/main/java/com/google/code/yanf4j/core/impl/AbstractController.java index 2109c1773..bdb1d0aad 100644 --- a/src/main/java/com/google/code/yanf4j/core/impl/AbstractController.java +++ b/src/main/java/com/google/code/yanf4j/core/impl/AbstractController.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.core.impl; @@ -33,12 +27,9 @@ import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ThreadPoolExecutor; - import net.rubyeye.xmemcached.utils.AddrUtil; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import com.google.code.yanf4j.config.Configuration; import com.google.code.yanf4j.core.CodecFactory; import com.google.code.yanf4j.core.Controller; @@ -62,506 +53,489 @@ * @author dennis * */ -public abstract class AbstractController - implements - Controller, - ControllerLifeCycle { - - protected Statistics statistics = new DefaultStatistics(); - protected long statisticsInterval; - - protected static final Logger log = LoggerFactory - .getLogger(AbstractController.class); - /** - * controller state listener list - */ - protected CopyOnWriteArrayList stateListeners = new CopyOnWriteArrayList(); - /** - * Event handler - */ - protected Handler handler; - /** - * Codec Factory - */ - - protected CodecFactory codecFactory; - /** - * Status - */ - protected volatile boolean started; - /** - * local bind address - */ - protected InetSocketAddress localSocketAddress; - /** - * Read event processing thread count - */ - protected int readThreadCount; - protected int writeThreadCount; - protected int dispatchMessageThreadCount; - protected Configuration configuration; - protected Dispatcher readEventDispatcher, dispatchMessageDispatcher, - writeEventDispatcher; - protected long sessionTimeout; - protected boolean handleReadWriteConcurrently = true; - - protected int soTimeout; - - /** - * Socket options - */ - @SuppressWarnings("unchecked") - protected Map socketOptions = new HashMap(); - - @SuppressWarnings("unchecked") - public void setSocketOptions(Map socketOptions) { - if (socketOptions == null) { - throw new NullPointerException("Null socketOptions"); - } - this.socketOptions = socketOptions; - } - - /** - * Connected session set - */ - protected Set sessionSet = new ConcurrentHashSet(); - private Thread shutdownHookThread; - private volatile boolean isHutdownHookCalled = false; - - public final int getDispatchMessageThreadCount() { - return dispatchMessageThreadCount; - } - - public final void setDispatchMessageThreadCount( - int dispatchMessageThreadPoolSize) { - if (started) { - throw new IllegalStateException("Controller is started"); - } - if (dispatchMessageThreadPoolSize < 0) { - throw new IllegalArgumentException( - "dispatchMessageThreadPoolSize<0"); - } - dispatchMessageThreadCount = dispatchMessageThreadPoolSize; - } - - public long getSessionIdleTimeout() { - return configuration.getSessionIdleTimeout(); - } - - /** - * Build write queue for session - * - * @return - */ - protected Queue buildQueue() { - return new LinkedTransferQueue(); - } - - public void setSessionIdleTimeout(long sessionIdleTimeout) { - configuration.setSessionIdleTimeout(sessionIdleTimeout); - - } - - public long getSessionTimeout() { - return sessionTimeout; - } - - public void setSessionTimeout(long sessionTimeout) { - this.sessionTimeout = sessionTimeout; - } - - public int getSoTimeout() { - return soTimeout; - } - - public void setSoTimeout(int timeout) { - soTimeout = timeout; - } - - public AbstractController() { - this(new Configuration(), null, null); - } - - public double getReceiveThroughputLimit() { - return statistics.getReceiveThroughputLimit(); - } - - public double getSendThroughputLimit() { - return statistics.getSendThroughputLimit(); - } - - public void setReceiveThroughputLimit(double receiveThroughputLimit) { - statistics.setReceiveThroughputLimit(receiveThroughputLimit); - - } - - public void setSendThroughputLimit(double sendThroughputLimit) { - statistics.setSendThroughputLimit(sendThroughputLimit); - } - - public AbstractController(Configuration configuration) { - this(configuration, null, null); - - } - - public AbstractController(Configuration configuration, - CodecFactory codecFactory) { - this(configuration, null, codecFactory); - } - - public AbstractController(Configuration configuration, Handler handler, - CodecFactory codecFactory) { - init(configuration, handler, codecFactory); - } - - private synchronized void init(Configuration configuration, Handler handler, - CodecFactory codecFactory) { - setHandler(handler); - setCodecFactory(codecFactory); - setConfiguration(configuration); - setReadThreadCount(configuration.getReadThreadCount()); - setWriteThreadCount(configuration.getWriteThreadCount()); - setDispatchMessageThreadCount( - configuration.getDispatchMessageThreadCount()); - setHandleReadWriteConcurrently( - configuration.isHandleReadWriteConcurrently()); - setSoTimeout(configuration.getSoTimeout()); - setStatisticsConfig(configuration); - setReceiveThroughputLimit(-0.1d); - setStarted(false); - } - - void setStarted(boolean started) { - this.started = started; - } - - private void setStatisticsConfig(Configuration configuration) { - if (configuration.isStatisticsServer()) { - statistics = new SimpleStatistics(); - statisticsInterval = configuration.getStatisticsInterval(); - - } else { - statistics = new DefaultStatistics(); - statisticsInterval = -1; - } - } - - public Configuration getConfiguration() { - return configuration; - } - - public void setConfiguration(Configuration configuration) { - if (configuration == null) { - throw new IllegalArgumentException("Null Configuration"); - } - this.configuration = configuration; - } - - public InetSocketAddress getLocalSocketAddress() { - return localSocketAddress; - } - - public void setLocalSocketAddress(InetSocketAddress inetSocketAddress) { - localSocketAddress = inetSocketAddress; - } - - public void onAccept(SelectionKey sk) throws IOException { - statistics.statisticsAccept(); - } - - public void onConnect(SelectionKey key) throws IOException { - throw new UnsupportedOperationException(); - } - - public void addStateListener(ControllerStateListener listener) { - stateListeners.add(listener); - } - - public void removeStateListener(ControllerStateListener listener) { - stateListeners.remove(listener); - } - - public boolean isHandleReadWriteConcurrently() { - return handleReadWriteConcurrently; - } - - public void setHandleReadWriteConcurrently( - boolean handleReadWriteConcurrently) { - this.handleReadWriteConcurrently = handleReadWriteConcurrently; - } - - public int getReadThreadCount() { - return readThreadCount; - } - - public void setReadThreadCount(int readThreadCount) { - if (started) { - throw new IllegalStateException(); - } - if (readThreadCount < 0) { - throw new IllegalArgumentException("readThreadCount<0"); - } - this.readThreadCount = readThreadCount; - } - - public final int getWriteThreadCount() { - return writeThreadCount; - } - - public final void setWriteThreadCount(int writeThreadCount) { - if (started) { - throw new IllegalStateException(); - } - if (writeThreadCount < 0) { - throw new IllegalArgumentException("readThreadCount<0"); - } - this.writeThreadCount = writeThreadCount; - } - - public Handler getHandler() { - return handler; - } - - public void setHandler(Handler handler) { - if (started) { - throw new IllegalStateException("The Controller have started"); - } - this.handler = handler; - } - - public int getPort() { - if (localSocketAddress != null) { - return localSocketAddress.getPort(); - } - throw new NullPointerException("Controller is not binded"); - } - - public synchronized void start() throws IOException { - if (isStarted()) { - return; - } - if (getHandler() == null) { - throw new IOException("The handler is null"); - } - if (getCodecFactory() == null) { - setCodecFactory(new ByteBufferCodecFactory()); - } - setStarted(true); - setReadEventDispatcher(DispatcherFactory.newDispatcher( - getReadThreadCount(), new ThreadPoolExecutor.CallerRunsPolicy(), - "xmemcached-read-thread")); - setWriteEventDispatcher( - DispatcherFactory.newDispatcher(getWriteThreadCount(), - new ThreadPoolExecutor.CallerRunsPolicy(), - "xmemcached-write-thread")); - setDispatchMessageDispatcher( - DispatcherFactory.newDispatcher(getDispatchMessageThreadCount(), - new ThreadPoolExecutor.CallerRunsPolicy(), - "xmemcached-dispatch-thread")); - startStatistics(); - start0(); - notifyStarted(); - if (AddrUtil.isEnableShutDownHook()) { - shutdownHookThread = new Thread() { - @Override - public void run() { - try { - isHutdownHookCalled = true; - AbstractController.this.stop(); - } catch (IOException e) { - log.error("Stop controller fail", e); - } - } - }; - Runtime.getRuntime().addShutdownHook(shutdownHookThread); - } - log.info("The Controller started at " + localSocketAddress + " ..."); - } - - protected abstract void start0() throws IOException; - - void setDispatchMessageDispatcher(Dispatcher dispatcher) { - Dispatcher oldDispatcher = dispatchMessageDispatcher; - dispatchMessageDispatcher = dispatcher; - if (oldDispatcher != null) { - oldDispatcher.stop(); - } - } - - Dispatcher getReadEventDispatcher() { - return readEventDispatcher; - } - - void setReadEventDispatcher(Dispatcher dispatcher) { - Dispatcher oldDispatcher = readEventDispatcher; - readEventDispatcher = dispatcher; - if (oldDispatcher != null) { - oldDispatcher.stop(); - } - } - - void setWriteEventDispatcher(Dispatcher dispatcher) { - Dispatcher oldDispatcher = writeEventDispatcher; - writeEventDispatcher = dispatcher; - if (oldDispatcher != null) { - oldDispatcher.stop(); - } - } - - private final void startStatistics() { - statistics.start(); - } - - public void notifyStarted() { - for (ControllerStateListener stateListener : stateListeners) { - stateListener.onStarted(this); - } - } - - public boolean isStarted() { - return started; - } - - public final Statistics getStatistics() { - return statistics; - } - - public final CodecFactory getCodecFactory() { - return codecFactory; - } - - public final void setCodecFactory(CodecFactory codecFactory) { - this.codecFactory = codecFactory; - } - - public void notifyReady() { - for (ControllerStateListener stateListener : stateListeners) { - stateListener.onReady(this); - } - } - - public final synchronized void unregisterSession(Session session) { - sessionSet.remove(session); - if (sessionSet.size() == 0) { - notifyAllSessionClosed(); - notifyAll(); - } - } - - public void checkStatisticsForRestart() { - if (statisticsInterval > 0 && System.currentTimeMillis() - - statistics.getStartedTime() > statisticsInterval * 1000) { - statistics.restart(); - } - } - - public final synchronized void registerSession(Session session) { - if (started) { - sessionSet.add(session); - } else { - session.close(); - } - - } - - public void stop() throws IOException { - synchronized (this) { - if (!isStarted()) { - return; - } - setStarted(false); - } - for (Session session : sessionSet) { - session.close(); - } - stopStatistics(); - stopDispatcher(); - sessionSet.clear(); - notifyStopped(); - clearStateListeners(); - stop0(); - if (AddrUtil.isEnableShutDownHook() && shutdownHookThread != null - && !isHutdownHookCalled) { - Runtime.getRuntime().removeShutdownHook(shutdownHookThread); - } - log.info("Controller has been stopped."); - } - - protected abstract void stop0() throws IOException; - - private final void stopDispatcher() { - if (readEventDispatcher != null) { - readEventDispatcher.stop(); - } - if (dispatchMessageDispatcher != null) { - dispatchMessageDispatcher.stop(); - } - if (writeEventDispatcher != null) { - writeEventDispatcher.stop(); - } - } - - private final void stopStatistics() { - statistics.stop(); - } - - private final void clearStateListeners() { - stateListeners.clear(); - } - - public final void notifyException(Throwable t) { - for (ControllerStateListener stateListener : stateListeners) { - stateListener.onException(this, t); - } - } - - public final void notifyStopped() { - for (ControllerStateListener stateListener : stateListeners) { - stateListener.onStopped(this); - } - } - - public final void notifyAllSessionClosed() { - for (ControllerStateListener stateListener : stateListeners) { - stateListener.onAllSessionClosed(this); - } - } - - public Set getSessionSet() { - return Collections.unmodifiableSet(sessionSet); - } - - public void setSocketOption(SocketOption socketOption, T value) { - if (socketOption == null) { - throw new NullPointerException("Null socketOption"); - } - if (value == null) { - throw new NullPointerException("Null value"); - } - if (!socketOption.type().equals(value.getClass())) { - throw new IllegalArgumentException("Expected " - + socketOption.type().getSimpleName() + " value,but givend " - + value.getClass().getSimpleName()); - } - socketOptions.put(socketOption, value); - } - - @SuppressWarnings("unchecked") - public T getSocketOption(SocketOption socketOption) { - return (T) socketOptions.get(socketOption); - } - - /** - * Bind localhost address - * - * @param inetSocketAddress - * @throws IOException - */ - public void bind(InetSocketAddress inetSocketAddress) throws IOException { - if (inetSocketAddress == null) { - throw new IllegalArgumentException("Null inetSocketAddress"); - } - setLocalSocketAddress(inetSocketAddress); - start(); - } +public abstract class AbstractController implements Controller, ControllerLifeCycle { + + protected Statistics statistics = new DefaultStatistics(); + protected long statisticsInterval; + + protected static final Logger log = LoggerFactory.getLogger(AbstractController.class); + /** + * controller state listener list + */ + protected CopyOnWriteArrayList stateListeners = + new CopyOnWriteArrayList(); + /** + * Event handler + */ + protected Handler handler; + /** + * Codec Factory + */ + + protected CodecFactory codecFactory; + /** + * Status + */ + protected volatile boolean started; + /** + * local bind address + */ + protected InetSocketAddress localSocketAddress; + /** + * Read event processing thread count + */ + protected int readThreadCount; + protected int writeThreadCount; + protected int dispatchMessageThreadCount; + protected Configuration configuration; + protected Dispatcher readEventDispatcher, dispatchMessageDispatcher, writeEventDispatcher; + protected long sessionTimeout; + protected boolean handleReadWriteConcurrently = true; + + protected int soTimeout; + + /** + * Socket options + */ + @SuppressWarnings("unchecked") + protected Map socketOptions = new HashMap(); + + @SuppressWarnings("unchecked") + public void setSocketOptions(Map socketOptions) { + if (socketOptions == null) { + throw new NullPointerException("Null socketOptions"); + } + this.socketOptions = socketOptions; + } + + /** + * Connected session set + */ + protected Set sessionSet = new ConcurrentHashSet(); + private Thread shutdownHookThread; + private volatile boolean isHutdownHookCalled = false; + + public final int getDispatchMessageThreadCount() { + return dispatchMessageThreadCount; + } + + public final void setDispatchMessageThreadCount(int dispatchMessageThreadPoolSize) { + if (started) { + throw new IllegalStateException("Controller is started"); + } + if (dispatchMessageThreadPoolSize < 0) { + throw new IllegalArgumentException("dispatchMessageThreadPoolSize<0"); + } + dispatchMessageThreadCount = dispatchMessageThreadPoolSize; + } + + public long getSessionIdleTimeout() { + return configuration.getSessionIdleTimeout(); + } + + /** + * Build write queue for session + * + * @return + */ + protected Queue buildQueue() { + return new LinkedTransferQueue(); + } + + public void setSessionIdleTimeout(long sessionIdleTimeout) { + configuration.setSessionIdleTimeout(sessionIdleTimeout); + + } + + public long getSessionTimeout() { + return sessionTimeout; + } + + public void setSessionTimeout(long sessionTimeout) { + this.sessionTimeout = sessionTimeout; + } + + public int getSoTimeout() { + return soTimeout; + } + + public void setSoTimeout(int timeout) { + soTimeout = timeout; + } + + public AbstractController() { + this(new Configuration(), null, null); + } + + public double getReceiveThroughputLimit() { + return statistics.getReceiveThroughputLimit(); + } + + public double getSendThroughputLimit() { + return statistics.getSendThroughputLimit(); + } + + public void setReceiveThroughputLimit(double receiveThroughputLimit) { + statistics.setReceiveThroughputLimit(receiveThroughputLimit); + + } + + public void setSendThroughputLimit(double sendThroughputLimit) { + statistics.setSendThroughputLimit(sendThroughputLimit); + } + + public AbstractController(Configuration configuration) { + this(configuration, null, null); + + } + + public AbstractController(Configuration configuration, CodecFactory codecFactory) { + this(configuration, null, codecFactory); + } + + public AbstractController(Configuration configuration, Handler handler, + CodecFactory codecFactory) { + init(configuration, handler, codecFactory); + } + + private synchronized void init(Configuration configuration, Handler handler, + CodecFactory codecFactory) { + setHandler(handler); + setCodecFactory(codecFactory); + setConfiguration(configuration); + setReadThreadCount(configuration.getReadThreadCount()); + setWriteThreadCount(configuration.getWriteThreadCount()); + setDispatchMessageThreadCount(configuration.getDispatchMessageThreadCount()); + setHandleReadWriteConcurrently(configuration.isHandleReadWriteConcurrently()); + setSoTimeout(configuration.getSoTimeout()); + setStatisticsConfig(configuration); + setReceiveThroughputLimit(-0.1d); + setStarted(false); + } + + void setStarted(boolean started) { + this.started = started; + } + + private void setStatisticsConfig(Configuration configuration) { + if (configuration.isStatisticsServer()) { + statistics = new SimpleStatistics(); + statisticsInterval = configuration.getStatisticsInterval(); + + } else { + statistics = new DefaultStatistics(); + statisticsInterval = -1; + } + } + + public Configuration getConfiguration() { + return configuration; + } + + public void setConfiguration(Configuration configuration) { + if (configuration == null) { + throw new IllegalArgumentException("Null Configuration"); + } + this.configuration = configuration; + } + + public InetSocketAddress getLocalSocketAddress() { + return localSocketAddress; + } + + public void setLocalSocketAddress(InetSocketAddress inetSocketAddress) { + localSocketAddress = inetSocketAddress; + } + + public void onAccept(SelectionKey sk) throws IOException { + statistics.statisticsAccept(); + } + + public void onConnect(SelectionKey key) throws IOException { + throw new UnsupportedOperationException(); + } + + public void addStateListener(ControllerStateListener listener) { + stateListeners.add(listener); + } + + public void removeStateListener(ControllerStateListener listener) { + stateListeners.remove(listener); + } + + public boolean isHandleReadWriteConcurrently() { + return handleReadWriteConcurrently; + } + + public void setHandleReadWriteConcurrently(boolean handleReadWriteConcurrently) { + this.handleReadWriteConcurrently = handleReadWriteConcurrently; + } + + public int getReadThreadCount() { + return readThreadCount; + } + + public void setReadThreadCount(int readThreadCount) { + if (started) { + throw new IllegalStateException(); + } + if (readThreadCount < 0) { + throw new IllegalArgumentException("readThreadCount<0"); + } + this.readThreadCount = readThreadCount; + } + + public final int getWriteThreadCount() { + return writeThreadCount; + } + + public final void setWriteThreadCount(int writeThreadCount) { + if (started) { + throw new IllegalStateException(); + } + if (writeThreadCount < 0) { + throw new IllegalArgumentException("readThreadCount<0"); + } + this.writeThreadCount = writeThreadCount; + } + + public Handler getHandler() { + return handler; + } + + public void setHandler(Handler handler) { + if (started) { + throw new IllegalStateException("The Controller have started"); + } + this.handler = handler; + } + + public int getPort() { + if (localSocketAddress != null) { + return localSocketAddress.getPort(); + } + throw new NullPointerException("Controller is not binded"); + } + + public synchronized void start() throws IOException { + if (isStarted()) { + return; + } + if (getHandler() == null) { + throw new IOException("The handler is null"); + } + if (getCodecFactory() == null) { + setCodecFactory(new ByteBufferCodecFactory()); + } + setStarted(true); + setReadEventDispatcher(DispatcherFactory.newDispatcher(getReadThreadCount(), + new ThreadPoolExecutor.CallerRunsPolicy(), "xmemcached-read-thread")); + setWriteEventDispatcher(DispatcherFactory.newDispatcher(getWriteThreadCount(), + new ThreadPoolExecutor.CallerRunsPolicy(), "xmemcached-write-thread")); + setDispatchMessageDispatcher(DispatcherFactory.newDispatcher(getDispatchMessageThreadCount(), + new ThreadPoolExecutor.CallerRunsPolicy(), "xmemcached-dispatch-thread")); + startStatistics(); + start0(); + notifyStarted(); + if (AddrUtil.isEnableShutDownHook()) { + shutdownHookThread = new Thread() { + @Override + public void run() { + try { + isHutdownHookCalled = true; + AbstractController.this.stop(); + } catch (IOException e) { + log.error("Stop controller fail", e); + } + } + }; + Runtime.getRuntime().addShutdownHook(shutdownHookThread); + } + log.info("The Controller started at " + localSocketAddress + " ..."); + } + + protected abstract void start0() throws IOException; + + void setDispatchMessageDispatcher(Dispatcher dispatcher) { + Dispatcher oldDispatcher = dispatchMessageDispatcher; + dispatchMessageDispatcher = dispatcher; + if (oldDispatcher != null) { + oldDispatcher.stop(); + } + } + + Dispatcher getReadEventDispatcher() { + return readEventDispatcher; + } + + void setReadEventDispatcher(Dispatcher dispatcher) { + Dispatcher oldDispatcher = readEventDispatcher; + readEventDispatcher = dispatcher; + if (oldDispatcher != null) { + oldDispatcher.stop(); + } + } + + void setWriteEventDispatcher(Dispatcher dispatcher) { + Dispatcher oldDispatcher = writeEventDispatcher; + writeEventDispatcher = dispatcher; + if (oldDispatcher != null) { + oldDispatcher.stop(); + } + } + + private final void startStatistics() { + statistics.start(); + } + + public void notifyStarted() { + for (ControllerStateListener stateListener : stateListeners) { + stateListener.onStarted(this); + } + } + + public boolean isStarted() { + return started; + } + + public final Statistics getStatistics() { + return statistics; + } + + public final CodecFactory getCodecFactory() { + return codecFactory; + } + + public final void setCodecFactory(CodecFactory codecFactory) { + this.codecFactory = codecFactory; + } + + public void notifyReady() { + for (ControllerStateListener stateListener : stateListeners) { + stateListener.onReady(this); + } + } + + public final synchronized void unregisterSession(Session session) { + sessionSet.remove(session); + if (sessionSet.size() == 0) { + notifyAllSessionClosed(); + notifyAll(); + } + } + + public void checkStatisticsForRestart() { + if (statisticsInterval > 0 + && System.currentTimeMillis() - statistics.getStartedTime() > statisticsInterval * 1000) { + statistics.restart(); + } + } + + public final synchronized void registerSession(Session session) { + if (started) { + sessionSet.add(session); + } else { + session.close(); + } + + } + + public void stop() throws IOException { + synchronized (this) { + if (!isStarted()) { + return; + } + setStarted(false); + } + for (Session session : sessionSet) { + session.close(); + } + stopStatistics(); + stopDispatcher(); + sessionSet.clear(); + notifyStopped(); + clearStateListeners(); + stop0(); + if (AddrUtil.isEnableShutDownHook() && shutdownHookThread != null && !isHutdownHookCalled) { + Runtime.getRuntime().removeShutdownHook(shutdownHookThread); + } + log.info("Controller has been stopped."); + } + + protected abstract void stop0() throws IOException; + + private final void stopDispatcher() { + if (readEventDispatcher != null) { + readEventDispatcher.stop(); + } + if (dispatchMessageDispatcher != null) { + dispatchMessageDispatcher.stop(); + } + if (writeEventDispatcher != null) { + writeEventDispatcher.stop(); + } + } + + private final void stopStatistics() { + statistics.stop(); + } + + private final void clearStateListeners() { + stateListeners.clear(); + } + + public final void notifyException(Throwable t) { + for (ControllerStateListener stateListener : stateListeners) { + stateListener.onException(this, t); + } + } + + public final void notifyStopped() { + for (ControllerStateListener stateListener : stateListeners) { + stateListener.onStopped(this); + } + } + + public final void notifyAllSessionClosed() { + for (ControllerStateListener stateListener : stateListeners) { + stateListener.onAllSessionClosed(this); + } + } + + public Set getSessionSet() { + return Collections.unmodifiableSet(sessionSet); + } + + public void setSocketOption(SocketOption socketOption, T value) { + if (socketOption == null) { + throw new NullPointerException("Null socketOption"); + } + if (value == null) { + throw new NullPointerException("Null value"); + } + if (!socketOption.type().equals(value.getClass())) { + throw new IllegalArgumentException("Expected " + socketOption.type().getSimpleName() + + " value,but givend " + value.getClass().getSimpleName()); + } + socketOptions.put(socketOption, value); + } + + @SuppressWarnings("unchecked") + public T getSocketOption(SocketOption socketOption) { + return (T) socketOptions.get(socketOption); + } + + /** + * Bind localhost address + * + * @param inetSocketAddress + * @throws IOException + */ + public void bind(InetSocketAddress inetSocketAddress) throws IOException { + if (inetSocketAddress == null) { + throw new IllegalArgumentException("Null inetSocketAddress"); + } + setLocalSocketAddress(inetSocketAddress); + start(); + } } diff --git a/src/main/java/com/google/code/yanf4j/core/impl/AbstractSession.java b/src/main/java/com/google/code/yanf4j/core/impl/AbstractSession.java index 1b4ca4853..2a8f0b1da 100644 --- a/src/main/java/com/google/code/yanf4j/core/impl/AbstractSession.java +++ b/src/main/java/com/google/code/yanf4j/core/impl/AbstractSession.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.core.impl; @@ -34,10 +28,8 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.ReentrantLock; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import com.google.code.yanf4j.buffer.IoBuffer; import com.google.code.yanf4j.core.CodecFactory; import com.google.code.yanf4j.core.Dispatcher; @@ -56,400 +48,392 @@ */ public abstract class AbstractSession implements Session { - protected IoBuffer readBuffer; - protected static final Logger log = LoggerFactory - .getLogger(AbstractSession.class); + protected IoBuffer readBuffer; + protected static final Logger log = LoggerFactory.getLogger(AbstractSession.class); + + protected final ConcurrentHashMap attributes = + new ConcurrentHashMap(); - protected final ConcurrentHashMap attributes = new ConcurrentHashMap(); + protected Queue writeQueue; - protected Queue writeQueue; + protected long sessionIdleTimeout; - protected long sessionIdleTimeout; + protected long sessionTimeout; - protected long sessionTimeout; + public long getSessionIdleTimeout() { + return sessionIdleTimeout; + } - public long getSessionIdleTimeout() { - return sessionIdleTimeout; - } + public void setSessionIdleTimeout(long sessionIdleTimeout) { + this.sessionIdleTimeout = sessionIdleTimeout; + } - public void setSessionIdleTimeout(long sessionIdleTimeout) { - this.sessionIdleTimeout = sessionIdleTimeout; - } + public long getSessionTimeout() { + return sessionTimeout; + } - public long getSessionTimeout() { - return sessionTimeout; - } + public void setSessionTimeout(long sessionTimeout) { + this.sessionTimeout = sessionTimeout; + } - public void setSessionTimeout(long sessionTimeout) { - this.sessionTimeout = sessionTimeout; - } + public Queue getWriteQueue() { + return writeQueue; + } - public Queue getWriteQueue() { - return writeQueue; - } + public Statistics getStatistics() { + return statistics; + } - public Statistics getStatistics() { - return statistics; - } + public Handler getHandler() { + return handler; + } - public Handler getHandler() { - return handler; - } + public Dispatcher getDispatchMessageDispatcher() { + return dispatchMessageDispatcher; + } - public Dispatcher getDispatchMessageDispatcher() { - return dispatchMessageDispatcher; - } + public ReentrantLock getWriteLock() { + return writeLock; + } - public ReentrantLock getWriteLock() { - return writeLock; - } + protected CodecFactory.Encoder encoder; + protected CodecFactory.Decoder decoder; - protected CodecFactory.Encoder encoder; - protected CodecFactory.Decoder decoder; + protected volatile boolean closed; - protected volatile boolean closed; + protected Statistics statistics; - protected Statistics statistics; + protected Handler handler; - protected Handler handler; + protected boolean loopback; - protected boolean loopback; - - public AtomicLong lastOperationTimeStamp = new AtomicLong(0); + public AtomicLong lastOperationTimeStamp = new AtomicLong(0); - protected AtomicLong scheduleWritenBytes = new AtomicLong(0); + protected AtomicLong scheduleWritenBytes = new AtomicLong(0); - protected final Dispatcher dispatchMessageDispatcher; - protected boolean useBlockingWrite = false; - protected boolean useBlockingRead = true; - protected boolean handleReadWriteConcurrently = true; - - public abstract void decode(); - - public void updateTimeStamp() { - lastOperationTimeStamp.set(System.currentTimeMillis()); - } - - public long getLastOperationTimeStamp() { - return lastOperationTimeStamp.get(); - } - - public final boolean isHandleReadWriteConcurrently() { - return handleReadWriteConcurrently; - } - - public final void setHandleReadWriteConcurrently( - boolean handleReadWriteConcurrently) { - this.handleReadWriteConcurrently = handleReadWriteConcurrently; - } - - public long getScheduleWritenBytes() { - return scheduleWritenBytes.get(); - } - - public CodecFactory.Encoder getEncoder() { - return encoder; - } - - public void setEncoder(CodecFactory.Encoder encoder) { - this.encoder = encoder; - } - - public CodecFactory.Decoder getDecoder() { - return decoder; - } - - public IoBuffer getReadBuffer() { - return readBuffer; - } - - public void setReadBuffer(IoBuffer readBuffer) { - this.readBuffer = readBuffer; - } - - public void setDecoder(CodecFactory.Decoder decoder) { - this.decoder = decoder; - } - - public final ByteOrder getReadBufferByteOrder() { - if (readBuffer == null) { - throw new IllegalStateException(); - } - return readBuffer.order(); - } - - public final void setReadBufferByteOrder(ByteOrder readBufferByteOrder) { - if (readBuffer == null) { - throw new NullPointerException("Null ReadBuffer"); - } - readBuffer.order(readBufferByteOrder); - } - - // synchronized,prevent reactors invoking this method concurrently. - protected synchronized void onIdle() { - try { - // check twice - if (isIdle()) { - updateTimeStamp(); - handler.onSessionIdle(this); - } - } catch (Throwable e) { - onException(e); - } - } - - protected void onConnected() { - try { - handler.onSessionConnected(this); - } catch (Throwable e) { - onException(e); - } - } - - public void onExpired() { - try { - if (isExpired()) { - handler.onSessionExpired(this); - } - } catch (Throwable e) { - onException(e); - } - } - - protected abstract WriteMessage wrapMessage(Object msg, - Future writeFuture); - - /** - * Pre-Process WriteMessage before writing to channel - * - * @param writeMessage - * @return - */ - protected WriteMessage preprocessWriteMessage(WriteMessage writeMessage) { - return writeMessage; - } - - protected void dispatchReceivedMessage(final Object message) { - if (dispatchMessageDispatcher == null) { - long start = -1; - if (statistics != null && statistics.isStatistics()) { - start = System.currentTimeMillis(); - } - onMessage(message, this); - if (start != -1) { - statistics - .statisticsProcess(System.currentTimeMillis() - start); - } - } else { - - dispatchMessageDispatcher.dispatch(new Runnable() { - public void run() { - long start = -1; - if (statistics != null && statistics.isStatistics()) { - start = System.currentTimeMillis(); - } - onMessage(message, AbstractSession.this); - if (start != -1) { - statistics.statisticsProcess( - System.currentTimeMillis() - start); - } - } - - }); - } - - } - - private void onMessage(final Object message, Session session) { - try { - handler.onMessageReceived(session, message); - } catch (Throwable e) { - onException(e); - } - } - - public final boolean isClosed() { - return closed; - } - - public final void setClosed(boolean closed) { - this.closed = closed; - } - - public void close() { - synchronized (this) { - if (isClosed()) { - return; - } - setClosed(true); - } - try { - closeChannel(); - clearAttributes(); - log.debug("session closed"); - } catch (IOException e) { - onException(e); - log.error("Close session error", e); - } finally { - onClosed(); - } - } - - protected abstract void closeChannel() throws IOException; - - public void onException(Throwable e) { - handler.onExceptionCaught(this, e); - } - - protected void onClosed() { - try { - handler.onSessionClosed(this); - } catch (Throwable e) { - onException(e); - } - } - - public void setAttribute(String key, Object value) { - attributes.put(key, value); - } - - public Object setAttributeIfAbsent(String key, Object value) { - return attributes.putIfAbsent(key, value); - } - - public void removeAttribute(String key) { - attributes.remove(key); - } - - public Object getAttribute(String key) { - return attributes.get(key); - } - - public void clearAttributes() { - attributes.clear(); - } - - public synchronized void start() { - log.debug("session started"); - onStarted(); - start0(); - } - - protected abstract void start0(); - - protected void onStarted() { - try { - handler.onSessionStarted(this); - } catch (Throwable e) { - onException(e); - } - } - - protected ReentrantLock writeLock = new ReentrantLock(); - - protected AtomicReference currentMessage = new LinkedTransferQueue.PaddedAtomicReference( - null); - - static final class FailFuture implements Future { - - public boolean cancel(boolean mayInterruptIfRunning) { - return Boolean.FALSE; - } - - public Boolean get() throws InterruptedException, ExecutionException { - return Boolean.FALSE; - } - - public Boolean get(long timeout, TimeUnit unit) - throws InterruptedException, ExecutionException, - TimeoutException { - return Boolean.FALSE; - } - - public boolean isCancelled() { - return false; - } - - public boolean isDone() { - return true; - } - - } - - public void write(Object packet) { - if (closed) { - return; - } - WriteMessage message = wrapMessage(packet, null); - scheduleWritenBytes.addAndGet(message.getWriteBuffer().remaining()); - writeFromUserCode(message); - } - - public abstract void writeFromUserCode(WriteMessage message); - - public final boolean isLoopbackConnection() { - return loopback; - } - - public boolean isUseBlockingWrite() { - return useBlockingWrite; - } - - public void setUseBlockingWrite(boolean useBlockingWrite) { - this.useBlockingWrite = useBlockingWrite; - } - - public boolean isUseBlockingRead() { - return useBlockingRead; - } - - public void setUseBlockingRead(boolean useBlockingRead) { - this.useBlockingRead = useBlockingRead; - } - - public void clearWriteQueue() { - writeQueue.clear(); - } - - public boolean isExpired() { - return false; - } - - public boolean isIdle() { - long lastOpTimestamp = getLastOperationTimeStamp(); - return lastOpTimestamp > 0 && System.currentTimeMillis() - - lastOpTimestamp > sessionIdleTimeout; - } - - public AbstractSession(SessionConfig sessionConfig) { - super(); - lastOperationTimeStamp.set(System.currentTimeMillis()); - statistics = sessionConfig.statistics; - handler = sessionConfig.handler; - writeQueue = sessionConfig.queue; - encoder = sessionConfig.codecFactory.getEncoder(); - decoder = sessionConfig.codecFactory.getDecoder(); - dispatchMessageDispatcher = sessionConfig.dispatchMessageDispatcher; - handleReadWriteConcurrently = sessionConfig.handleReadWriteConcurrently; - sessionTimeout = sessionConfig.sessionTimeout; - sessionIdleTimeout = sessionConfig.sessionIdelTimeout; - } - - public long transferTo(long position, long count, FileChannel target) - throws IOException { - throw new UnsupportedOperationException(); - } - - public long transferFrom(long position, long count, FileChannel source) - throws IOException { - throw new UnsupportedOperationException(); - } - - protected void onCreated() { - try { - handler.onSessionCreated(this); - } catch (Throwable e) { - onException(e); - } - } + protected final Dispatcher dispatchMessageDispatcher; + protected boolean useBlockingWrite = false; + protected boolean useBlockingRead = true; + protected boolean handleReadWriteConcurrently = true; + + public abstract void decode(); + + public void updateTimeStamp() { + lastOperationTimeStamp.set(System.currentTimeMillis()); + } + + public long getLastOperationTimeStamp() { + return lastOperationTimeStamp.get(); + } + + public final boolean isHandleReadWriteConcurrently() { + return handleReadWriteConcurrently; + } + + public final void setHandleReadWriteConcurrently(boolean handleReadWriteConcurrently) { + this.handleReadWriteConcurrently = handleReadWriteConcurrently; + } + + public long getScheduleWritenBytes() { + return scheduleWritenBytes.get(); + } + + public CodecFactory.Encoder getEncoder() { + return encoder; + } + + public void setEncoder(CodecFactory.Encoder encoder) { + this.encoder = encoder; + } + + public CodecFactory.Decoder getDecoder() { + return decoder; + } + + public IoBuffer getReadBuffer() { + return readBuffer; + } + + public void setReadBuffer(IoBuffer readBuffer) { + this.readBuffer = readBuffer; + } + + public void setDecoder(CodecFactory.Decoder decoder) { + this.decoder = decoder; + } + + public final ByteOrder getReadBufferByteOrder() { + if (readBuffer == null) { + throw new IllegalStateException(); + } + return readBuffer.order(); + } + + public final void setReadBufferByteOrder(ByteOrder readBufferByteOrder) { + if (readBuffer == null) { + throw new NullPointerException("Null ReadBuffer"); + } + readBuffer.order(readBufferByteOrder); + } + + // synchronized,prevent reactors invoking this method concurrently. + protected synchronized void onIdle() { + try { + // check twice + if (isIdle()) { + updateTimeStamp(); + handler.onSessionIdle(this); + } + } catch (Throwable e) { + onException(e); + } + } + + protected void onConnected() { + try { + handler.onSessionConnected(this); + } catch (Throwable e) { + onException(e); + } + } + + public void onExpired() { + try { + if (isExpired()) { + handler.onSessionExpired(this); + } + } catch (Throwable e) { + onException(e); + } + } + + protected abstract WriteMessage wrapMessage(Object msg, Future writeFuture); + + /** + * Pre-Process WriteMessage before writing to channel + * + * @param writeMessage + * @return + */ + protected WriteMessage preprocessWriteMessage(WriteMessage writeMessage) { + return writeMessage; + } + + protected void dispatchReceivedMessage(final Object message) { + if (dispatchMessageDispatcher == null) { + long start = -1; + if (statistics != null && statistics.isStatistics()) { + start = System.currentTimeMillis(); + } + onMessage(message, this); + if (start != -1) { + statistics.statisticsProcess(System.currentTimeMillis() - start); + } + } else { + + dispatchMessageDispatcher.dispatch(new Runnable() { + public void run() { + long start = -1; + if (statistics != null && statistics.isStatistics()) { + start = System.currentTimeMillis(); + } + onMessage(message, AbstractSession.this); + if (start != -1) { + statistics.statisticsProcess(System.currentTimeMillis() - start); + } + } + + }); + } + + } + + private void onMessage(final Object message, Session session) { + try { + handler.onMessageReceived(session, message); + } catch (Throwable e) { + onException(e); + } + } + + public final boolean isClosed() { + return closed; + } + + public final void setClosed(boolean closed) { + this.closed = closed; + } + + public void close() { + synchronized (this) { + if (isClosed()) { + return; + } + setClosed(true); + } + try { + closeChannel(); + clearAttributes(); + log.debug("session closed"); + } catch (IOException e) { + onException(e); + log.error("Close session error", e); + } finally { + onClosed(); + } + } + + protected abstract void closeChannel() throws IOException; + + public void onException(Throwable e) { + handler.onExceptionCaught(this, e); + } + + protected void onClosed() { + try { + handler.onSessionClosed(this); + } catch (Throwable e) { + onException(e); + } + } + + public void setAttribute(String key, Object value) { + attributes.put(key, value); + } + + public Object setAttributeIfAbsent(String key, Object value) { + return attributes.putIfAbsent(key, value); + } + + public void removeAttribute(String key) { + attributes.remove(key); + } + + public Object getAttribute(String key) { + return attributes.get(key); + } + + public void clearAttributes() { + attributes.clear(); + } + + public synchronized void start() { + log.debug("session started"); + onStarted(); + start0(); + } + + protected abstract void start0(); + + protected void onStarted() { + try { + handler.onSessionStarted(this); + } catch (Throwable e) { + onException(e); + } + } + + protected ReentrantLock writeLock = new ReentrantLock(); + + protected AtomicReference currentMessage = + new LinkedTransferQueue.PaddedAtomicReference(null); + + static final class FailFuture implements Future { + + public boolean cancel(boolean mayInterruptIfRunning) { + return Boolean.FALSE; + } + + public Boolean get() throws InterruptedException, ExecutionException { + return Boolean.FALSE; + } + + public Boolean get(long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + return Boolean.FALSE; + } + + public boolean isCancelled() { + return false; + } + + public boolean isDone() { + return true; + } + + } + + public void write(Object packet) { + if (closed) { + return; + } + WriteMessage message = wrapMessage(packet, null); + scheduleWritenBytes.addAndGet(message.getWriteBuffer().remaining()); + writeFromUserCode(message); + } + + public abstract void writeFromUserCode(WriteMessage message); + + public final boolean isLoopbackConnection() { + return loopback; + } + + public boolean isUseBlockingWrite() { + return useBlockingWrite; + } + + public void setUseBlockingWrite(boolean useBlockingWrite) { + this.useBlockingWrite = useBlockingWrite; + } + + public boolean isUseBlockingRead() { + return useBlockingRead; + } + + public void setUseBlockingRead(boolean useBlockingRead) { + this.useBlockingRead = useBlockingRead; + } + + public void clearWriteQueue() { + writeQueue.clear(); + } + + public boolean isExpired() { + return false; + } + + public boolean isIdle() { + long lastOpTimestamp = getLastOperationTimeStamp(); + return lastOpTimestamp > 0 && System.currentTimeMillis() - lastOpTimestamp > sessionIdleTimeout; + } + + public AbstractSession(SessionConfig sessionConfig) { + super(); + lastOperationTimeStamp.set(System.currentTimeMillis()); + statistics = sessionConfig.statistics; + handler = sessionConfig.handler; + writeQueue = sessionConfig.queue; + encoder = sessionConfig.codecFactory.getEncoder(); + decoder = sessionConfig.codecFactory.getDecoder(); + dispatchMessageDispatcher = sessionConfig.dispatchMessageDispatcher; + handleReadWriteConcurrently = sessionConfig.handleReadWriteConcurrently; + sessionTimeout = sessionConfig.sessionTimeout; + sessionIdleTimeout = sessionConfig.sessionIdelTimeout; + } + + public long transferTo(long position, long count, FileChannel target) throws IOException { + throw new UnsupportedOperationException(); + } + + public long transferFrom(long position, long count, FileChannel source) throws IOException { + throw new UnsupportedOperationException(); + } + + protected void onCreated() { + try { + handler.onSessionCreated(this); + } catch (Throwable e) { + onException(e); + } + } } diff --git a/src/main/java/com/google/code/yanf4j/core/impl/ByteBufferCodecFactory.java b/src/main/java/com/google/code/yanf4j/core/impl/ByteBufferCodecFactory.java index 4e3693dcd..85219a2e0 100644 --- a/src/main/java/com/google/code/yanf4j/core/impl/ByteBufferCodecFactory.java +++ b/src/main/java/com/google/code/yanf4j/core/impl/ByteBufferCodecFactory.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.core.impl; @@ -33,72 +27,70 @@ * */ public class ByteBufferCodecFactory implements CodecFactory { - static final IoBuffer EMPTY_BUFFER = IoBuffer.allocate(0); - - private boolean direct; - - public ByteBufferCodecFactory() { - this(false); - } - - public ByteBufferCodecFactory(boolean direct) { - super(); - this.direct = direct; - this.encoder = new ByteBufferEncoder(); - this.decoder = new ByteBufferDecoder(); - } - - public class ByteBufferDecoder implements Decoder { - - public Object decode(IoBuffer buff, Session session) { - if (buff == null) { - return null; - } - if (buff.remaining() == 0) { - return EMPTY_BUFFER; - } - byte[] bytes = new byte[buff.remaining()]; - buff.get(bytes); - IoBuffer result = IoBuffer.allocate(bytes.length, - ByteBufferCodecFactory.this.direct); - result.put(bytes); - result.flip(); - return result; - } - - } - - private Decoder decoder; - - public Decoder getDecoder() { - return this.decoder; - } - - public class ByteBufferEncoder implements Encoder { - - public IoBuffer encode(Object message, Session session) { - final IoBuffer msgBuffer = (IoBuffer) message; - if (msgBuffer == null) { - return null; - } - if (msgBuffer.remaining() == 0) { - return EMPTY_BUFFER; - } - byte[] bytes = new byte[msgBuffer.remaining()]; - msgBuffer.get(bytes); - IoBuffer result = IoBuffer.allocate(bytes.length, - ByteBufferCodecFactory.this.direct); - result.put(bytes); - result.flip(); - return result; - } - - } - - private Encoder encoder; - - public Encoder getEncoder() { - return this.encoder; - } + static final IoBuffer EMPTY_BUFFER = IoBuffer.allocate(0); + + private boolean direct; + + public ByteBufferCodecFactory() { + this(false); + } + + public ByteBufferCodecFactory(boolean direct) { + super(); + this.direct = direct; + this.encoder = new ByteBufferEncoder(); + this.decoder = new ByteBufferDecoder(); + } + + public class ByteBufferDecoder implements Decoder { + + public Object decode(IoBuffer buff, Session session) { + if (buff == null) { + return null; + } + if (buff.remaining() == 0) { + return EMPTY_BUFFER; + } + byte[] bytes = new byte[buff.remaining()]; + buff.get(bytes); + IoBuffer result = IoBuffer.allocate(bytes.length, ByteBufferCodecFactory.this.direct); + result.put(bytes); + result.flip(); + return result; + } + + } + + private Decoder decoder; + + public Decoder getDecoder() { + return this.decoder; + } + + public class ByteBufferEncoder implements Encoder { + + public IoBuffer encode(Object message, Session session) { + final IoBuffer msgBuffer = (IoBuffer) message; + if (msgBuffer == null) { + return null; + } + if (msgBuffer.remaining() == 0) { + return EMPTY_BUFFER; + } + byte[] bytes = new byte[msgBuffer.remaining()]; + msgBuffer.get(bytes); + IoBuffer result = IoBuffer.allocate(bytes.length, ByteBufferCodecFactory.this.direct); + result.put(bytes); + result.flip(); + return result; + } + + } + + private Encoder encoder; + + public Encoder getEncoder() { + return this.encoder; + } } diff --git a/src/main/java/com/google/code/yanf4j/core/impl/FutureImpl.java b/src/main/java/com/google/code/yanf4j/core/impl/FutureImpl.java index 55cb9f01b..389b8ec18 100644 --- a/src/main/java/com/google/code/yanf4j/core/impl/FutureImpl.java +++ b/src/main/java/com/google/code/yanf4j/core/impl/FutureImpl.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.core.impl; @@ -29,8 +23,8 @@ import java.util.concurrent.TimeoutException; /** - * Simple {@link Future} implementation, which uses synchronization - * {@link Object} to synchronize during the lifecycle. + * Simple {@link Future} implementation, which uses synchronization {@link Object} to synchronize + * during the lifecycle. * * @see Future * @@ -38,142 +32,139 @@ */ public class FutureImpl implements Future { - private final Object sync; - - private boolean isDone; - - private boolean isCancelled; - private Throwable failure; - - protected R result; - - public FutureImpl() { - this(new Object()); - } - - public FutureImpl(Object sync) { - this.sync = sync; - } - - /** - * Get current result value without any blocking. - * - * @return current result value without any blocking. - */ - public R getResult() { - synchronized (this.sync) { - return this.result; - } - } - - /** - * Set the result value and notify about operation completion. - * - * @param result - * the result value - */ - public void setResult(R result) { - synchronized (this.sync) { - this.result = result; - notifyHaveResult(); - } - } - - /** - * {@inheritDoc} - */ - public boolean cancel(boolean mayInterruptIfRunning) { - synchronized (this.sync) { - this.isCancelled = true; - notifyHaveResult(); - return true; - } - } - - /** - * {@inheritDoc} - */ - public boolean isCancelled() { - synchronized (this.sync) { - return this.isCancelled; - } - } - - /** - * {@inheritDoc} - */ - public boolean isDone() { - synchronized (this.sync) { - return this.isDone; - } - } - - /** - * {@inheritDoc} - */ - public R get() throws InterruptedException, ExecutionException { - synchronized (this.sync) { - for (;;) { - if (this.isDone) { - if (this.isCancelled) { - throw new CancellationException(); - } else if (this.failure != null) { - throw new ExecutionException(this.failure); - } else if (this.result != null) { - return this.result; - } - } - - this.sync.wait(); - } - } - } - - /** - * {@inheritDoc} - */ - public R get(long timeout, TimeUnit unit) - throws InterruptedException, ExecutionException, TimeoutException { - long startTime = System.currentTimeMillis(); - long timeoutMillis = TimeUnit.MILLISECONDS.convert(timeout, unit); - synchronized (this.sync) { - for (;;) { - if (this.isDone) { - if (this.isCancelled) { - throw new CancellationException(); - } else if (this.failure != null) { - throw new ExecutionException(this.failure); - } else if (this.result != null) { - return this.result; - } - } else if (System.currentTimeMillis() - - startTime > timeoutMillis) { - throw new TimeoutException(); - } - - this.sync.wait(timeoutMillis); - } - } - } - - /** - * Notify about the failure, occured during asynchronous operation - * execution. - * - * @param failure - */ - public void failure(Throwable failure) { - synchronized (this.sync) { - this.failure = failure; - notifyHaveResult(); - } - } - - /** - * Notify blocked listeners threads about operation completion. - */ - protected void notifyHaveResult() { - this.isDone = true; - this.sync.notifyAll(); - } + private final Object sync; + + private boolean isDone; + + private boolean isCancelled; + private Throwable failure; + + protected R result; + + public FutureImpl() { + this(new Object()); + } + + public FutureImpl(Object sync) { + this.sync = sync; + } + + /** + * Get current result value without any blocking. + * + * @return current result value without any blocking. + */ + public R getResult() { + synchronized (this.sync) { + return this.result; + } + } + + /** + * Set the result value and notify about operation completion. + * + * @param result the result value + */ + public void setResult(R result) { + synchronized (this.sync) { + this.result = result; + notifyHaveResult(); + } + } + + /** + * {@inheritDoc} + */ + public boolean cancel(boolean mayInterruptIfRunning) { + synchronized (this.sync) { + this.isCancelled = true; + notifyHaveResult(); + return true; + } + } + + /** + * {@inheritDoc} + */ + public boolean isCancelled() { + synchronized (this.sync) { + return this.isCancelled; + } + } + + /** + * {@inheritDoc} + */ + public boolean isDone() { + synchronized (this.sync) { + return this.isDone; + } + } + + /** + * {@inheritDoc} + */ + public R get() throws InterruptedException, ExecutionException { + synchronized (this.sync) { + for (;;) { + if (this.isDone) { + if (this.isCancelled) { + throw new CancellationException(); + } else if (this.failure != null) { + throw new ExecutionException(this.failure); + } else if (this.result != null) { + return this.result; + } + } + + this.sync.wait(); + } + } + } + + /** + * {@inheritDoc} + */ + public R get(long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + long startTime = System.currentTimeMillis(); + long timeoutMillis = TimeUnit.MILLISECONDS.convert(timeout, unit); + synchronized (this.sync) { + for (;;) { + if (this.isDone) { + if (this.isCancelled) { + throw new CancellationException(); + } else if (this.failure != null) { + throw new ExecutionException(this.failure); + } else if (this.result != null) { + return this.result; + } + } else if (System.currentTimeMillis() - startTime > timeoutMillis) { + throw new TimeoutException(); + } + + this.sync.wait(timeoutMillis); + } + } + } + + /** + * Notify about the failure, occured during asynchronous operation execution. + * + * @param failure + */ + public void failure(Throwable failure) { + synchronized (this.sync) { + this.failure = failure; + notifyHaveResult(); + } + } + + /** + * Notify blocked listeners threads about operation completion. + */ + protected void notifyHaveResult() { + this.isDone = true; + this.sync.notifyAll(); + } } diff --git a/src/main/java/com/google/code/yanf4j/core/impl/FutureLockImpl.java b/src/main/java/com/google/code/yanf4j/core/impl/FutureLockImpl.java index 23b0fa683..4a9164310 100644 --- a/src/main/java/com/google/code/yanf4j/core/impl/FutureLockImpl.java +++ b/src/main/java/com/google/code/yanf4j/core/impl/FutureLockImpl.java @@ -1,215 +1,206 @@ -/* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2007-2008 Sun Microsystems, Inc. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can obtain - * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html - * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt. - * Sun designates this particular file as subject to the "Classpath" exception - * as provided by Sun in the GPL Version 2 section of the License file that - * accompanied this code. If applicable, add the following below the License - * Header, with the fields enclosed by brackets [] replaced by your own - * identifying information: "Portions Copyrighted [year] - * [name of copyright owner]" - * - * Contributor(s): - * - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - * - */ - -package com.google.code.yanf4j.core.impl; - -import java.util.concurrent.CancellationException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.locks.ReentrantLock; - -/** - * Simple {@link Future} implementation, which uses {@link ReentrantLock} to - * synchronize during the lifecycle. - * - * @see Future - * @see ReentrantLock - * - * @author Alexey Stashok - */ -public class FutureLockImpl implements Future { - - private final ReentrantLock lock; - - private boolean isDone; - - private CountDownLatch latch; - - private boolean isCancelled; - private Throwable failure; - - protected R result; - - public FutureLockImpl() { - this(new ReentrantLock()); - } - - public FutureLockImpl(ReentrantLock lock) { - this.lock = lock; - latch = new CountDownLatch(1); - } - - /** - * Get current result value without any blocking. - * - * @return current result value without any blocking. - */ - public R getResult() { - try { - lock.lock(); - return result; - } finally { - lock.unlock(); - } - } - - /** - * Set the result value and notify about operation completion. - * - * @param result - * the result value - */ - public void setResult(R result) { - try { - lock.lock(); - this.result = result; - notifyHaveResult(); - } finally { - lock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - public boolean cancel(boolean mayInterruptIfRunning) { - try { - lock.lock(); - isCancelled = true; - notifyHaveResult(); - return true; - } finally { - lock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - public boolean isCancelled() { - try { - lock.lock(); - return isCancelled; - } finally { - lock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - public boolean isDone() { - try { - lock.lock(); - return isDone; - } finally { - lock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - public R get() throws InterruptedException, ExecutionException { - latch.await(); - - try { - lock.lock(); - if (isCancelled) { - throw new CancellationException(); - } else if (failure != null) { - throw new ExecutionException(failure); - } - - return result; - } finally { - lock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - public R get(long timeout, TimeUnit unit) - throws InterruptedException, ExecutionException, TimeoutException { - boolean isTimeOut = !latch.await(timeout, unit); - try { - lock.lock(); - if (!isTimeOut) { - if (isCancelled) { - throw new CancellationException(); - } else if (failure != null) { - throw new ExecutionException(failure); - } - - return result; - } else { - throw new TimeoutException(); - } - } finally { - lock.unlock(); - } - } - - /** - * Notify about the failure, occured during asynchronous operation - * execution. - * - * @param failure - */ - public void failure(Throwable failure) { - try { - lock.lock(); - this.failure = failure; - notifyHaveResult(); - } finally { - lock.unlock(); - } - } - - /** - * Notify blocked listeners threads about operation completion. - */ - protected void notifyHaveResult() { - isDone = true; - latch.countDown(); - } -} +/* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007-2008 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU General Public License + * Version 2 only ("GPL") or the Common Development and Distribution License("CDDL") (collectively, + * the "License"). You may not use this file except in compliance with the License. You can obtain a + * copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html or + * glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific language governing + * permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each file and include the + * License file at glassfish/bootstrap/legal/LICENSE.txt. Sun designates this particular file as + * subject to the "Classpath" exception as provided by Sun in the GPL Version 2 section of the + * License file that accompanied this code. If applicable, add the following below the License + * Header, with the fields enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by only the CDDL or only the GPL Version 2, + * indicate your decision by adding "[Contributor] elects to include this software in this + * distribution under the [CDDL or GPL Version 2] license." If you don't indicate a single choice of + * license, a recipient has the option to distribute your version of this file under either the + * CDDL, the GPL Version 2 or to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such option by the copyright holder. + */ + +package com.google.code.yanf4j.core.impl; + +import java.util.concurrent.CancellationException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.locks.ReentrantLock; + +/** + * Simple {@link Future} implementation, which uses {@link ReentrantLock} to synchronize during the + * lifecycle. + * + * @see Future + * @see ReentrantLock + * + * @author Alexey Stashok + */ +public class FutureLockImpl implements Future { + + private final ReentrantLock lock; + + private boolean isDone; + + private CountDownLatch latch; + + private boolean isCancelled; + private Throwable failure; + + protected R result; + + public FutureLockImpl() { + this(new ReentrantLock()); + } + + public FutureLockImpl(ReentrantLock lock) { + this.lock = lock; + latch = new CountDownLatch(1); + } + + /** + * Get current result value without any blocking. + * + * @return current result value without any blocking. + */ + public R getResult() { + try { + lock.lock(); + return result; + } finally { + lock.unlock(); + } + } + + /** + * Set the result value and notify about operation completion. + * + * @param result the result value + */ + public void setResult(R result) { + try { + lock.lock(); + this.result = result; + notifyHaveResult(); + } finally { + lock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + public boolean cancel(boolean mayInterruptIfRunning) { + try { + lock.lock(); + isCancelled = true; + notifyHaveResult(); + return true; + } finally { + lock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + public boolean isCancelled() { + try { + lock.lock(); + return isCancelled; + } finally { + lock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + public boolean isDone() { + try { + lock.lock(); + return isDone; + } finally { + lock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + public R get() throws InterruptedException, ExecutionException { + latch.await(); + + try { + lock.lock(); + if (isCancelled) { + throw new CancellationException(); + } else if (failure != null) { + throw new ExecutionException(failure); + } + + return result; + } finally { + lock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + public R get(long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + boolean isTimeOut = !latch.await(timeout, unit); + try { + lock.lock(); + if (!isTimeOut) { + if (isCancelled) { + throw new CancellationException(); + } else if (failure != null) { + throw new ExecutionException(failure); + } + + return result; + } else { + throw new TimeoutException(); + } + } finally { + lock.unlock(); + } + } + + /** + * Notify about the failure, occured during asynchronous operation execution. + * + * @param failure + */ + public void failure(Throwable failure) { + try { + lock.lock(); + this.failure = failure; + notifyHaveResult(); + } finally { + lock.unlock(); + } + } + + /** + * Notify blocked listeners threads about operation completion. + */ + protected void notifyHaveResult() { + isDone = true; + latch.countDown(); + } +} diff --git a/src/main/java/com/google/code/yanf4j/core/impl/HandlerAdapter.java b/src/main/java/com/google/code/yanf4j/core/impl/HandlerAdapter.java index 043cdceff..0f48ae20b 100644 --- a/src/main/java/com/google/code/yanf4j/core/impl/HandlerAdapter.java +++ b/src/main/java/com/google/code/yanf4j/core/impl/HandlerAdapter.java @@ -1,30 +1,23 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.core.impl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import com.google.code.yanf4j.core.Handler; import com.google.code.yanf4j.core.Session; @@ -37,44 +30,42 @@ * */ public class HandlerAdapter implements Handler { - private static final Logger log = LoggerFactory - .getLogger(HandlerAdapter.class); + private static final Logger log = LoggerFactory.getLogger(HandlerAdapter.class); - public void onExceptionCaught(Session session, Throwable throwable) { + public void onExceptionCaught(Session session, Throwable throwable) { - } + } - public void onMessageSent(Session session, Object message) { + public void onMessageSent(Session session, Object message) { - } + } - public void onSessionConnected(Session session) { + public void onSessionConnected(Session session) { - } + } - public void onSessionStarted(Session session) { + public void onSessionStarted(Session session) { - } + } - public void onSessionCreated(Session session) { + public void onSessionCreated(Session session) { - } + } - public void onSessionClosed(Session session) { + public void onSessionClosed(Session session) { - } + } - public void onMessageReceived(Session session, Object message) { + public void onMessageReceived(Session session, Object message) { - } + } - public void onSessionIdle(Session session) { + public void onSessionIdle(Session session) { - } + } - public void onSessionExpired(Session session) { - log.warn("Session(" + session.getRemoteSocketAddress() - + ") is expired."); - } + public void onSessionExpired(Session session) { + log.warn("Session(" + session.getRemoteSocketAddress() + ") is expired."); + } } diff --git a/src/main/java/com/google/code/yanf4j/core/impl/PoolDispatcher.java b/src/main/java/com/google/code/yanf4j/core/impl/PoolDispatcher.java index 5deb5e8cf..ee06c459f 100644 --- a/src/main/java/com/google/code/yanf4j/core/impl/PoolDispatcher.java +++ b/src/main/java/com/google/code/yanf4j/core/impl/PoolDispatcher.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.core.impl; @@ -26,7 +20,6 @@ import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; - import com.google.code.yanf4j.core.Dispatcher; import com.google.code.yanf4j.util.WorkerThreadFactory; @@ -40,46 +33,42 @@ * */ public class PoolDispatcher implements Dispatcher { - public static final int DEFAULT_POOL_QUEUE_SIZE_FACTOR = 1000; - public static final float DEFAULT_MAX_POOL_SIZE_FACTOR = 1.25f; - private ThreadPoolExecutor threadPool; + public static final int DEFAULT_POOL_QUEUE_SIZE_FACTOR = 1000; + public static final float DEFAULT_MAX_POOL_SIZE_FACTOR = 1.25f; + private ThreadPoolExecutor threadPool; - public PoolDispatcher(int poolSize) { - this(poolSize, 60, TimeUnit.SECONDS, - new ThreadPoolExecutor.AbortPolicy(), "pool-dispatcher"); - } + public PoolDispatcher(int poolSize) { + this(poolSize, 60, TimeUnit.SECONDS, new ThreadPoolExecutor.AbortPolicy(), "pool-dispatcher"); + } - public PoolDispatcher(int poolSize, long keepAliveTime, TimeUnit unit, - RejectedExecutionHandler rejectedExecutionHandler, String prefix) { - this(poolSize, DEFAULT_POOL_QUEUE_SIZE_FACTOR, - DEFAULT_MAX_POOL_SIZE_FACTOR, keepAliveTime, unit, - rejectedExecutionHandler, prefix); - } + public PoolDispatcher(int poolSize, long keepAliveTime, TimeUnit unit, + RejectedExecutionHandler rejectedExecutionHandler, String prefix) { + this(poolSize, DEFAULT_POOL_QUEUE_SIZE_FACTOR, DEFAULT_MAX_POOL_SIZE_FACTOR, keepAliveTime, + unit, rejectedExecutionHandler, prefix); + } - public PoolDispatcher(int poolSize, int poolQueueSizeFactor, - float maxPoolSizeFactor, long keepAliveTime, TimeUnit unit, - RejectedExecutionHandler rejectedExecutionHandler, String prefix) { - this.threadPool = new ThreadPoolExecutor(poolSize, - (int) (maxPoolSizeFactor * poolSize), keepAliveTime, unit, - new ArrayBlockingQueue( - poolSize * poolQueueSizeFactor), - new WorkerThreadFactory(prefix)); - this.threadPool.setRejectedExecutionHandler(rejectedExecutionHandler); - } + public PoolDispatcher(int poolSize, int poolQueueSizeFactor, float maxPoolSizeFactor, + long keepAliveTime, TimeUnit unit, RejectedExecutionHandler rejectedExecutionHandler, + String prefix) { + this.threadPool = new ThreadPoolExecutor(poolSize, (int) (maxPoolSizeFactor * poolSize), + keepAliveTime, unit, new ArrayBlockingQueue(poolSize * poolQueueSizeFactor), + new WorkerThreadFactory(prefix)); + this.threadPool.setRejectedExecutionHandler(rejectedExecutionHandler); + } - public final void dispatch(Runnable r) { - if (!this.threadPool.isShutdown()) { - this.threadPool.execute(r); - } - } + public final void dispatch(Runnable r) { + if (!this.threadPool.isShutdown()) { + this.threadPool.execute(r); + } + } - public void stop() { - this.threadPool.shutdown(); - try { - this.threadPool.awaitTermination(1000, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } + public void stop() { + this.threadPool.shutdown(); + try { + this.threadPool.awaitTermination(1000, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } } diff --git a/src/main/java/com/google/code/yanf4j/core/impl/StandardSocketOption.java b/src/main/java/com/google/code/yanf4j/core/impl/StandardSocketOption.java index 9929b973e..ed8d288a9 100644 --- a/src/main/java/com/google/code/yanf4j/core/impl/StandardSocketOption.java +++ b/src/main/java/com/google/code/yanf4j/core/impl/StandardSocketOption.java @@ -1,30 +1,23 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.core.impl; import java.net.ServerSocket; import java.net.Socket; - import com.google.code.yanf4j.core.SocketOption; /** @@ -35,193 +28,173 @@ */ public class StandardSocketOption { - /** - * Keep connection alive. - * - *

- * The value of this socket option is a {@code Boolean} that represents - * whether the option is enabled or disabled. When the {@code SO_KEEPALIVE} - * option is enabled the operating system may use a keep-alive - * mechanism to periodically probe the other end of a connection when the - * connection is otherwise idle. The exact semantics of the keep alive - * mechanism is system dependent and therefore unspecified. - * - *

- * The initial value of this socket option is {@code FALSE}. The socket - * option may be enabled or disabled at any time. - * - * @see RFC 1122 * - * Requirements for Internet Hosts -- Communication Layers< /a> - * @see Socket#setKeepAlive - */ - public static final SocketOption SO_KEEPALIVE = new SocketOption( - "SO_KEEPALIVE", Boolean.class); - /** - * The size of the socket send buffer. - * - *

- * The value of this socket option is an {@code Integer} that is the size of - * the socket send buffer in bytes. The socket send buffer is an output - * buffer used by the networking implementation. It may need to be increased - * for high-volume connections. The value of the socket option is a - * hint to the implementation to size the buffer and the actual - * size may differ. The socket option can be queried to retrieve the actual - * size. - * - *

- * For datagram-oriented sockets, the size of the send buffer may limit the - * size of the datagrams that may be sent by the socket. Whether datagrams - * larger than the buffer size are sent or discarded is system dependent. - * - *

- * The initial/default size of the socket send buffer and the range of - * allowable values is system dependent although a negative size is not - * allowed. An attempt to set the socket send buffer to larger than its - * maximum size causes it to be set to its maximum size. - * - *

- * An implementation allows this socket option to be set before the socket - * is bound or connected. Whether an implementation allows the socket send - * buffer to be changed after the socket is bound is system dependent. - * - * @see Socket#setSendBufferSize - */ - public static final SocketOption SO_SNDBUF = new SocketOption( - "SO_SNDBUF", Integer.class); - /** - * The size of the socket receive buffer. - * - *

- * The value of this socket option is an {@code Integer} that is the size of - * the socket receive buffer in bytes. The socket receive buffer is an input - * buffer used by the networking implementation. It may need to be increased - * for high-volume connections or decreased to limit the possible backlog of - * incoming data. The value of the socket option is a hint to the - * implementation to size the buffer and the actual size may differ. - * - *

- * For datagram-oriented sockets, the size of the receive buffer may limit - * the size of the datagrams that can be received. Whether datagrams larger - * than the buffer size can be received is system dependent. Increasing the - * socket receive buffer may be important for cases where datagrams arrive - * in bursts faster than they can be processed. - * - *

- * In the case of stream-oriented sockets and the TCP/IP protocol, the size - * of the socket receive buffer may be used when advertising the size of the - * TCP receive window to the remote peer. - * - *

- * The initial/default size of the socket receive buffer and the range of - * allowable values is system dependent although a negative size is not - * allowed. An attempt to set the socket receive buffer to larger than its - * maximum size causes it to be set to its maximum size. - * - *

- * An implementation allows this socket option to be set before the socket - * is bound or connected. Whether an implementation allows the socket - * receive buffer to be changed after the socket is bound is system - * dependent. - * - * @see RFC 1323: TCP * - * Extensions for High Performance< /a> - * @see Socket#setReceiveBufferSize - * @see ServerSocket#setReceiveBufferSize - */ - public static final SocketOption SO_RCVBUF = new SocketOption( - "SO_RCVBUF", Integer.class); - /** - * Re-use address. - * - *

- * The value of this socket option is a {@code Boolean} that represents - * whether the option is enabled or disabled. The exact semantics of this - * socket option are socket type and system dependent. - * - *

- * In the case of stream-oriented sockets, this socket option will usually - * determine whether the socket can be bound to a socket address when a - * previous connection involving that socket address is in the - * TIME_WAIT state. On implementations where the semantics differ, - * and the socket option is not required to be enabled in order to bind the - * socket when a previous connection is in this state, then the - * implementation may choose to ignore this option. - * - *

- * For datagram-oriented sockets the socket option is used to allow multiple - * programs bind to the same address. This option should be enabled when the - * socket is to be used for Internet Protocol (IP) multicasting. - * - *

- * An implementation allows this socket option to be set before the socket - * is bound or connected. Changing the value of this socket option after the - * socket is bound has no effect. The default value of this socket option is - * system dependent. - * - * @see RFC 793: * - * Transmission Control Protocol< /a> - * @see ServerSocket#setReuseAddress - */ - public static final SocketOption SO_REUSEADDR = new SocketOption( - "SO_REUSEADDR", Boolean.class); - /** - * Linger on close if data is present. - * - *

- * The value of this socket option is an {@code Integer} that controls the - * action taken when unsent data is queued on the socket and a method to - * close the socket is invoked. If the value of the socket option is zero or - * greater, then it represents a timeout value, in seconds, known as the - * linger interval. The linger interval is the timeout for the - * {@code close} method to block while the operating system attempts to - * transmit the unsent data or it decides that it is unable to transmit the - * data. If the value of the socket option is less than zero then the option - * is disabled. In that case the {@code close} method does not wait until - * unsent data is transmitted; if possible the operating system will - * transmit any unsent data before the connection is closed. - * - *

- * This socket option is intended for use with sockets that are configured - * in {@link java.nio.channels.SelectableChannel#isBlocking() blocking} mode - * only. The behavior of the {@code close} method when this option is - * enabled on a non-blocking socket is not defined. - * - *

- * The initial value of this socket option is a negative value, meaning that - * the option is disabled. The option may be enabled, or the linger interval - * changed, at any time. The maximum value of the linger interval is system - * dependent. Setting the linger interval to a value that is greater than - * its maximum value causes the linger interval to be set to its maximum - * value. - * - * @see Socket#setSoLinger - */ - public static final SocketOption SO_LINGER = new SocketOption( - "SO_LINGER", Integer.class); - /** - * Disable the Nagle algorithm. - * - *

- * The value of this socket option is a {@code Boolean} that represents - * whether the option is enabled or disabled. The socket option is specific - * to stream-oriented sockets using the TCP/IP protocol. TCP/IP uses an - * algorithm known as The Nagle Algorithm to coalesce short - * segments and improve network efficiency. - * - *

- * The default value of this socket option is {@code FALSE}. The socket - * option should only be enabled in cases where it is known that the - * coalescing impacts performance. The socket option may be enabled at any - * time. In other words, the Nagle Algorithm can be disabled. Once the - * option is enabled, it is system dependent whether it can be subsequently - * disabled. If it cannot, then invoking the {@code setOption} method to - * disable the option has no effect. - * - * @see RFC 1122: * - * Requirements for Internet Hosts -- Communication Layers< /a> - * @see Socket#setTcpNoDelay - */ - public static final SocketOption TCP_NODELAY = new SocketOption( - "TCP_NODELAY", Boolean.class); + /** + * Keep connection alive. + * + *

+ * The value of this socket option is a {@code Boolean} that represents whether the option is + * enabled or disabled. When the {@code SO_KEEPALIVE} option is enabled the operating system may + * use a keep-alive mechanism to periodically probe the other end of a connection when + * the connection is otherwise idle. The exact semantics of the keep alive mechanism is system + * dependent and therefore unspecified. + * + *

+ * The initial value of this socket option is {@code FALSE}. The socket option may be enabled or + * disabled at any time. + * + * @see RFC 1122 * Requirements for Internet + * Hosts -- Communication Layers< /a> + * @see Socket#setKeepAlive + */ + public static final SocketOption SO_KEEPALIVE = + new SocketOption("SO_KEEPALIVE", Boolean.class); + /** + * The size of the socket send buffer. + * + *

+ * The value of this socket option is an {@code Integer} that is the size of the socket send + * buffer in bytes. The socket send buffer is an output buffer used by the networking + * implementation. It may need to be increased for high-volume connections. The value of the + * socket option is a hint to the implementation to size the buffer and the actual size + * may differ. The socket option can be queried to retrieve the actual size. + * + *

+ * For datagram-oriented sockets, the size of the send buffer may limit the size of the datagrams + * that may be sent by the socket. Whether datagrams larger than the buffer size are sent or + * discarded is system dependent. + * + *

+ * The initial/default size of the socket send buffer and the range of allowable values is system + * dependent although a negative size is not allowed. An attempt to set the socket send buffer to + * larger than its maximum size causes it to be set to its maximum size. + * + *

+ * An implementation allows this socket option to be set before the socket is bound or connected. + * Whether an implementation allows the socket send buffer to be changed after the socket is bound + * is system dependent. + * + * @see Socket#setSendBufferSize + */ + public static final SocketOption SO_SNDBUF = + new SocketOption("SO_SNDBUF", Integer.class); + /** + * The size of the socket receive buffer. + * + *

+ * The value of this socket option is an {@code Integer} that is the size of the socket receive + * buffer in bytes. The socket receive buffer is an input buffer used by the networking + * implementation. It may need to be increased for high-volume connections or decreased to limit + * the possible backlog of incoming data. The value of the socket option is a hint to the + * implementation to size the buffer and the actual size may differ. + * + *

+ * For datagram-oriented sockets, the size of the receive buffer may limit the size of the + * datagrams that can be received. Whether datagrams larger than the buffer size can be received + * is system dependent. Increasing the socket receive buffer may be important for cases where + * datagrams arrive in bursts faster than they can be processed. + * + *

+ * In the case of stream-oriented sockets and the TCP/IP protocol, the size of the socket receive + * buffer may be used when advertising the size of the TCP receive window to the remote peer. + * + *

+ * The initial/default size of the socket receive buffer and the range of allowable values is + * system dependent although a negative size is not allowed. An attempt to set the socket receive + * buffer to larger than its maximum size causes it to be set to its maximum size. + * + *

+ * An implementation allows this socket option to be set before the socket is bound or connected. + * Whether an implementation allows the socket receive buffer to be changed after the socket is + * bound is system dependent. + * + * @see RFC 1323: TCP * Extensions for High + * Performance< /a> + * @see Socket#setReceiveBufferSize + * @see ServerSocket#setReceiveBufferSize + */ + public static final SocketOption SO_RCVBUF = + new SocketOption("SO_RCVBUF", Integer.class); + /** + * Re-use address. + * + *

+ * The value of this socket option is a {@code Boolean} that represents whether the option is + * enabled or disabled. The exact semantics of this socket option are socket type and system + * dependent. + * + *

+ * In the case of stream-oriented sockets, this socket option will usually determine whether the + * socket can be bound to a socket address when a previous connection involving that socket + * address is in the TIME_WAIT state. On implementations where the semantics differ, and + * the socket option is not required to be enabled in order to bind the socket when a previous + * connection is in this state, then the implementation may choose to ignore this option. + * + *

+ * For datagram-oriented sockets the socket option is used to allow multiple programs bind to the + * same address. This option should be enabled when the socket is to be used for Internet Protocol + * (IP) multicasting. + * + *

+ * An implementation allows this socket option to be set before the socket is bound or connected. + * Changing the value of this socket option after the socket is bound has no effect. The default + * value of this socket option is system dependent. + * + * @see RFC 793: * Transmission Control + * Protocol< /a> + * @see ServerSocket#setReuseAddress + */ + public static final SocketOption SO_REUSEADDR = + new SocketOption("SO_REUSEADDR", Boolean.class); + /** + * Linger on close if data is present. + * + *

+ * The value of this socket option is an {@code Integer} that controls the action taken when + * unsent data is queued on the socket and a method to close the socket is invoked. If the value + * of the socket option is zero or greater, then it represents a timeout value, in seconds, known + * as the linger interval. The linger interval is the timeout for the {@code close} + * method to block while the operating system attempts to transmit the unsent data or it decides + * that it is unable to transmit the data. If the value of the socket option is less than zero + * then the option is disabled. In that case the {@code close} method does not wait until unsent + * data is transmitted; if possible the operating system will transmit any unsent data before the + * connection is closed. + * + *

+ * This socket option is intended for use with sockets that are configured in + * {@link java.nio.channels.SelectableChannel#isBlocking() blocking} mode only. The behavior of + * the {@code close} method when this option is enabled on a non-blocking socket is not defined. + * + *

+ * The initial value of this socket option is a negative value, meaning that the option is + * disabled. The option may be enabled, or the linger interval changed, at any time. The maximum + * value of the linger interval is system dependent. Setting the linger interval to a value that + * is greater than its maximum value causes the linger interval to be set to its maximum value. + * + * @see Socket#setSoLinger + */ + public static final SocketOption SO_LINGER = + new SocketOption("SO_LINGER", Integer.class); + /** + * Disable the Nagle algorithm. + * + *

+ * The value of this socket option is a {@code Boolean} that represents whether the option is + * enabled or disabled. The socket option is specific to stream-oriented sockets using the TCP/IP + * protocol. TCP/IP uses an algorithm known as The Nagle Algorithm to coalesce short + * segments and improve network efficiency. + * + *

+ * The default value of this socket option is {@code FALSE}. The socket option should only be + * enabled in cases where it is known that the coalescing impacts performance. The socket option + * may be enabled at any time. In other words, the Nagle Algorithm can be disabled. Once the + * option is enabled, it is system dependent whether it can be subsequently disabled. If it + * cannot, then invoking the {@code setOption} method to disable the option has no effect. + * + * @see RFC 1122: * Requirements for Internet + * Hosts -- Communication Layers< /a> + * @see Socket#setTcpNoDelay + */ + public static final SocketOption TCP_NODELAY = + new SocketOption("TCP_NODELAY", Boolean.class); } diff --git a/src/main/java/com/google/code/yanf4j/core/impl/TextLineCodecFactory.java b/src/main/java/com/google/code/yanf4j/core/impl/TextLineCodecFactory.java index 3a23f2d31..45cc2f258 100644 --- a/src/main/java/com/google/code/yanf4j/core/impl/TextLineCodecFactory.java +++ b/src/main/java/com/google/code/yanf4j/core/impl/TextLineCodecFactory.java @@ -1,31 +1,24 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.core.impl; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; - import com.google.code.yanf4j.buffer.IoBuffer; import com.google.code.yanf4j.core.CodecFactory; import com.google.code.yanf4j.core.Session; @@ -36,91 +29,89 @@ * Text line codec factory * * @author dennis - * + * */ public class TextLineCodecFactory implements CodecFactory { - public static final IoBuffer SPLIT = IoBuffer.wrap("\r\n".getBytes()); - - private static final ByteBufferMatcher SPLIT_PATTERN = new ShiftAndByteBufferMatcher( - SPLIT); - - public static final String DEFAULT_CHARSET_NAME = "utf-8"; - - private Charset charset; - - public TextLineCodecFactory() { - this.charset = Charset.forName(DEFAULT_CHARSET_NAME); - } - - public TextLineCodecFactory(String charsetName) { - this.charset = Charset.forName(charsetName); - } - - class StringDecoder implements Decoder { - public Object decode(IoBuffer buffer, Session session) { - String result = null; - int index = SPLIT_PATTERN.matchFirst(buffer); - if (index >= 0) { - int limit = buffer.limit(); - buffer.limit(index); - CharBuffer charBuffer = TextLineCodecFactory.this.charset - .decode(buffer.buf()); - result = charBuffer.toString(); - buffer.limit(limit); - buffer.position(index + SPLIT.remaining()); - - } - return result; - } - } - - private Decoder decoder = new StringDecoder(); - - public Decoder getDecoder() { - return this.decoder; - - } - - class StringEncoder implements Encoder { - public IoBuffer encode(Object msg, Session session) { - if (msg == null) { - return null; - } - String message = (String) msg; - ByteBuffer buff = TextLineCodecFactory.this.charset.encode(message); - byte[] bs = new byte[buff.remaining() + SPLIT.remaining()]; - int len = buff.remaining(); - System.arraycopy(buff.array(), buff.position(), bs, 0, len); - bs[len] = 13; // \r - bs[len + 1] = 10; // \n - IoBuffer resultBuffer = IoBuffer.wrap(bs); - - return resultBuffer; - } - } - - private Encoder encoder = new StringEncoder(); - - public Encoder getEncoder() { - return this.encoder; - } - - // public static void main(String args[]) { - // TextLineCodecFactory codecFactory = new TextLineCodecFactory(); - // Encoder encoder = codecFactory.getEncoder(); - // long sum = 0; - // for (int i = 0; i < 100000; i++) { - // sum += encoder.encode("hello", null).remaining(); - // } - // - // long start = System.currentTimeMillis(); - // - // for (int i = 0; i < 10000000; i++) { - // sum += encoder.encode("hello", null).remaining(); - // } - // long cost = System.currentTimeMillis() - start; - // System.out.println("sum=" + sum + ",cost = " + cost + " ms."); - // } + public static final IoBuffer SPLIT = IoBuffer.wrap("\r\n".getBytes()); + + private static final ByteBufferMatcher SPLIT_PATTERN = new ShiftAndByteBufferMatcher(SPLIT); + + public static final String DEFAULT_CHARSET_NAME = "utf-8"; + + private Charset charset; + + public TextLineCodecFactory() { + this.charset = Charset.forName(DEFAULT_CHARSET_NAME); + } + + public TextLineCodecFactory(String charsetName) { + this.charset = Charset.forName(charsetName); + } + + class StringDecoder implements Decoder { + public Object decode(IoBuffer buffer, Session session) { + String result = null; + int index = SPLIT_PATTERN.matchFirst(buffer); + if (index >= 0) { + int limit = buffer.limit(); + buffer.limit(index); + CharBuffer charBuffer = TextLineCodecFactory.this.charset.decode(buffer.buf()); + result = charBuffer.toString(); + buffer.limit(limit); + buffer.position(index + SPLIT.remaining()); + + } + return result; + } + } + + private Decoder decoder = new StringDecoder(); + + public Decoder getDecoder() { + return this.decoder; + + } + + class StringEncoder implements Encoder { + public IoBuffer encode(Object msg, Session session) { + if (msg == null) { + return null; + } + String message = (String) msg; + ByteBuffer buff = TextLineCodecFactory.this.charset.encode(message); + byte[] bs = new byte[buff.remaining() + SPLIT.remaining()]; + int len = buff.remaining(); + System.arraycopy(buff.array(), buff.position(), bs, 0, len); + bs[len] = 13; // \r + bs[len + 1] = 10; // \n + IoBuffer resultBuffer = IoBuffer.wrap(bs); + + return resultBuffer; + } + } + + private Encoder encoder = new StringEncoder(); + + public Encoder getEncoder() { + return this.encoder; + } + + // public static void main(String args[]) { + // TextLineCodecFactory codecFactory = new TextLineCodecFactory(); + // Encoder encoder = codecFactory.getEncoder(); + // long sum = 0; + // for (int i = 0; i < 100000; i++) { + // sum += encoder.encode("hello", null).remaining(); + // } + // + // long start = System.currentTimeMillis(); + // + // for (int i = 0; i < 10000000; i++) { + // sum += encoder.encode("hello", null).remaining(); + // } + // long cost = System.currentTimeMillis() - start; + // System.out.println("sum=" + sum + ",cost = " + cost + " ms."); + // } } diff --git a/src/main/java/com/google/code/yanf4j/core/impl/WriteMessageImpl.java b/src/main/java/com/google/code/yanf4j/core/impl/WriteMessageImpl.java index f5c998413..89efa1d90 100644 --- a/src/main/java/com/google/code/yanf4j/core/impl/WriteMessageImpl.java +++ b/src/main/java/com/google/code/yanf4j/core/impl/WriteMessageImpl.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.core.impl; @@ -33,51 +27,51 @@ */ public class WriteMessageImpl implements WriteMessage { - protected Object message; + protected Object message; - protected IoBuffer buffer; + protected IoBuffer buffer; - protected FutureImpl writeFuture; + protected FutureImpl writeFuture; - protected boolean writing; + protected boolean writing; - public final void writing() { - this.writing = true; - } + public final void writing() { + this.writing = true; + } - public final boolean isWriting() { - return this.writing; - } + public final boolean isWriting() { + return this.writing; + } - public WriteMessageImpl(Object message, FutureImpl writeFuture) { - this.message = message; - this.writeFuture = writeFuture; - } + public WriteMessageImpl(Object message, FutureImpl writeFuture) { + this.message = message; + this.writeFuture = writeFuture; + } - /* - * (non-Javadoc) - * - * @see com.google.code.yanf4j.nio.IWriteMessage#getBuffers() - */ - public synchronized final IoBuffer getWriteBuffer() { - return this.buffer; - } + /* + * (non-Javadoc) + * + * @see com.google.code.yanf4j.nio.IWriteMessage#getBuffers() + */ + public synchronized final IoBuffer getWriteBuffer() { + return this.buffer; + } - public synchronized final void setWriteBuffer(IoBuffer buffers) { - this.buffer = buffers; + public synchronized final void setWriteBuffer(IoBuffer buffers) { + this.buffer = buffers; - } + } - public final FutureImpl getWriteFuture() { - return this.writeFuture; - } + public final FutureImpl getWriteFuture() { + return this.writeFuture; + } - /* - * (non-Javadoc) - * - * @see com.google.code.yanf4j.nio.IWriteMessage#getMessage() - */ - public final Object getMessage() { - return this.message; - } -} \ No newline at end of file + /* + * (non-Javadoc) + * + * @see com.google.code.yanf4j.nio.IWriteMessage#getMessage() + */ + public final Object getMessage() { + return this.message; + } +} diff --git a/src/main/java/com/google/code/yanf4j/core/package.html b/src/main/java/com/google/code/yanf4j/core/package.html index 244a4f9e4..99a97bcfb 100644 --- a/src/main/java/com/google/code/yanf4j/core/package.html +++ b/src/main/java/com/google/code/yanf4j/core/package.html @@ -1,14 +1,10 @@ - - + - -Networking core package - - - -

Networking core package

- - - + + Networking core package + + +

Networking core package

+ + \ No newline at end of file diff --git a/src/main/java/com/google/code/yanf4j/nio/NioSession.java b/src/main/java/com/google/code/yanf4j/nio/NioSession.java index 51932f9e6..e96c4677e 100644 --- a/src/main/java/com/google/code/yanf4j/nio/NioSession.java +++ b/src/main/java/com/google/code/yanf4j/nio/NioSession.java @@ -1,19 +1,15 @@ /** - *Copyright [2009-2010] [dennis zhuang] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang] Licensed 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 com.google.code.yanf4j.nio; import java.nio.channels.SelectableChannel; import java.nio.channels.Selector; - import com.google.code.yanf4j.core.EventType; import com.google.code.yanf4j.core.Session; @@ -24,33 +20,33 @@ * */ public interface NioSession extends Session { - /** - * When io event occured - * - * @param event - * @param selector - */ - public void onEvent(EventType event, Selector selector); + /** + * When io event occured + * + * @param event + * @param selector + */ + public void onEvent(EventType event, Selector selector); - /** - * Enable read event - * - * @param selector - */ - public void enableRead(Selector selector); + /** + * Enable read event + * + * @param selector + */ + public void enableRead(Selector selector); - /** - * Enable write event - * - * @param selector - */ - public void enableWrite(Selector selector); + /** + * Enable write event + * + * @param selector + */ + public void enableWrite(Selector selector); - /** - * return the channel for this connection - * - * @return - */ + /** + * return the channel for this connection + * + * @return + */ - public SelectableChannel channel(); + public SelectableChannel channel(); } diff --git a/src/main/java/com/google/code/yanf4j/nio/NioSessionConfig.java b/src/main/java/com/google/code/yanf4j/nio/NioSessionConfig.java index ea5248820..a158b8e4f 100644 --- a/src/main/java/com/google/code/yanf4j/nio/NioSessionConfig.java +++ b/src/main/java/com/google/code/yanf4j/nio/NioSessionConfig.java @@ -1,30 +1,23 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.nio; import java.nio.channels.SelectableChannel; import java.util.Queue; - import com.google.code.yanf4j.core.CodecFactory; import com.google.code.yanf4j.core.Dispatcher; import com.google.code.yanf4j.core.Handler; @@ -41,20 +34,17 @@ */ public class NioSessionConfig extends SessionConfig { - public final SelectableChannel selectableChannel; - public final SelectorManager selectorManager; + public final SelectableChannel selectableChannel; + public final SelectorManager selectorManager; - public NioSessionConfig(SelectableChannel sc, Handler handler, - SelectorManager reactor, CodecFactory codecFactory, - Statistics statistics, Queue queue, - Dispatcher dispatchMessageDispatcher, - boolean handleReadWriteConcurrently, long sessionTimeout, - long sessionIdleTimeout) { - super(handler, codecFactory, statistics, queue, - dispatchMessageDispatcher, handleReadWriteConcurrently, - sessionTimeout, sessionIdleTimeout); - this.selectableChannel = sc; - this.selectorManager = reactor; - } + public NioSessionConfig(SelectableChannel sc, Handler handler, SelectorManager reactor, + CodecFactory codecFactory, Statistics statistics, Queue queue, + Dispatcher dispatchMessageDispatcher, boolean handleReadWriteConcurrently, + long sessionTimeout, long sessionIdleTimeout) { + super(handler, codecFactory, statistics, queue, dispatchMessageDispatcher, + handleReadWriteConcurrently, sessionTimeout, sessionIdleTimeout); + this.selectableChannel = sc; + this.selectorManager = reactor; + } } diff --git a/src/main/java/com/google/code/yanf4j/nio/SelectionKeyHandler.java b/src/main/java/com/google/code/yanf4j/nio/SelectionKeyHandler.java index 9a44b17f4..3abb774e7 100644 --- a/src/main/java/com/google/code/yanf4j/nio/SelectionKeyHandler.java +++ b/src/main/java/com/google/code/yanf4j/nio/SelectionKeyHandler.java @@ -1,15 +1,12 @@ package com.google.code.yanf4j.nio; /** - *Copyright [2008-2009] [dennis zhuang] - *Licensed 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 + * Copyright [2008-2009] [dennis zhuang] Licensed 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 */ import java.io.IOException; import java.nio.channels.SelectionKey; @@ -22,15 +19,15 @@ * */ public interface SelectionKeyHandler { - public void onAccept(SelectionKey sk) throws IOException; + public void onAccept(SelectionKey sk) throws IOException; - public void closeSelectionKey(SelectionKey key); + public void closeSelectionKey(SelectionKey key); - public void onWrite(SelectionKey key); + public void onWrite(SelectionKey key); - public void onRead(SelectionKey key); + public void onRead(SelectionKey key); - public void onConnect(SelectionKey key) throws IOException; + public void onConnect(SelectionKey key) throws IOException; - public void closeChannel(Selector selector) throws IOException; + public void closeChannel(Selector selector) throws IOException; } diff --git a/src/main/java/com/google/code/yanf4j/nio/TCPController.java b/src/main/java/com/google/code/yanf4j/nio/TCPController.java index 1a9b28370..0ab4ea199 100644 --- a/src/main/java/com/google/code/yanf4j/nio/TCPController.java +++ b/src/main/java/com/google/code/yanf4j/nio/TCPController.java @@ -1,13 +1,10 @@ /** - *Copyright [2008-2009] [dennis zhuang] - *Licensed 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 + * Copyright [2008-2009] [dennis zhuang] Licensed 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 com.google.code.yanf4j.nio; @@ -19,7 +16,6 @@ import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; - import com.google.code.yanf4j.config.Configuration; import com.google.code.yanf4j.core.CodecFactory; import com.google.code.yanf4j.core.EventType; @@ -35,147 +31,135 @@ */ public class TCPController extends SocketChannelController { - private ServerSocketChannel serverSocketChannel; - - /** - * Accept backlog queue size - */ - private int backlog = 500; // default 500 - - public int getBacklog() { - return this.backlog; - } - - public void setBacklog(int backlog) { - if (isStarted()) { - throw new IllegalStateException(); - } - if (backlog < 0) { - throw new IllegalArgumentException("backlog<0"); - } - this.backlog = backlog; - } - - public TCPController() { - super(); - } - - public TCPController(Configuration configuration) { - super(configuration, null, null); - - } - - public TCPController(Configuration configuration, - CodecFactory codecFactory) { - super(configuration, null, codecFactory); - } - - public TCPController(Configuration configuration, Handler handler, - CodecFactory codecFactory) { - super(configuration, handler, codecFactory); - } - - private int connectionTime, latency, bandwidth; - - public void setPerformancePreferences(int connectionTime, int latency, - int bandwidth) { - this.connectionTime = connectionTime; - this.latency = latency; - this.bandwidth = bandwidth; - } - - @Override - protected void doStart() throws IOException { - this.serverSocketChannel = ServerSocketChannel.open(); - this.serverSocketChannel.socket().setSoTimeout(this.soTimeout); - if (this.connectionTime != 0 || this.latency != 0 - || this.bandwidth != 0) { - this.serverSocketChannel.socket().setPerformancePreferences( - this.connectionTime, this.latency, this.bandwidth); - } - this.serverSocketChannel.configureBlocking(false); - - if (this.socketOptions.get(StandardSocketOption.SO_REUSEADDR) != null) { - this.serverSocketChannel.socket() - .setReuseAddress(StandardSocketOption.SO_REUSEADDR.type() - .cast(this.socketOptions - .get(StandardSocketOption.SO_REUSEADDR))); - } - if (this.socketOptions.get(StandardSocketOption.SO_RCVBUF) != null) { - this.serverSocketChannel.socket() - .setReceiveBufferSize(StandardSocketOption.SO_RCVBUF.type() - .cast(this.socketOptions - .get(StandardSocketOption.SO_RCVBUF))); - - } - if (this.localSocketAddress != null) { - this.serverSocketChannel.socket().bind(this.localSocketAddress, - this.backlog); - } else { - this.serverSocketChannel.socket() - .bind(new InetSocketAddress("localhost", 0), this.backlog); - } - setLocalSocketAddress((InetSocketAddress) this.serverSocketChannel - .socket().getLocalSocketAddress()); - this.selectorManager.registerChannel(this.serverSocketChannel, - SelectionKey.OP_ACCEPT, null); - } - - @Override - public void onAccept(SelectionKey selectionKey) throws IOException { - // �������رգ�ȡ������ - if (!this.serverSocketChannel.isOpen()) { - selectionKey.cancel(); - return; - } - SocketChannel sc = null; - try { - sc = this.serverSocketChannel.accept(); - if (sc != null) { - configureSocketChannel(sc); - Session session = buildSession(sc); - // enable read - this.selectorManager.registerSession(session, - EventType.ENABLE_READ); - session.start(); - super.onAccept(selectionKey); // for statistics - } else { - log.debug("Accept fail"); - } - } catch (IOException e) { - closeAcceptChannel(selectionKey, sc); - log.error("Accept connection error", e); - notifyException(e); - } - } - - /** - * - * @param sk - * @param sc - * @throws IOException - * @throws SocketException - */ - private void closeAcceptChannel(SelectionKey sk, SocketChannel sc) - throws IOException, SocketException { - if (sk != null) { - sk.cancel(); - } - if (sc != null) { - sc.socket().setSoLinger(true, 0); // await TIME_WAIT status - sc.socket().shutdownOutput(); - sc.close(); - } - } - - public void closeChannel(Selector selector) throws IOException { - if (this.serverSocketChannel != null) { - this.serverSocketChannel.close(); - } - } - - public void unbind() throws IOException { - stop(); - } - -} \ No newline at end of file + private ServerSocketChannel serverSocketChannel; + + /** + * Accept backlog queue size + */ + private int backlog = 500; // default 500 + + public int getBacklog() { + return this.backlog; + } + + public void setBacklog(int backlog) { + if (isStarted()) { + throw new IllegalStateException(); + } + if (backlog < 0) { + throw new IllegalArgumentException("backlog<0"); + } + this.backlog = backlog; + } + + public TCPController() { + super(); + } + + public TCPController(Configuration configuration) { + super(configuration, null, null); + + } + + public TCPController(Configuration configuration, CodecFactory codecFactory) { + super(configuration, null, codecFactory); + } + + public TCPController(Configuration configuration, Handler handler, CodecFactory codecFactory) { + super(configuration, handler, codecFactory); + } + + private int connectionTime, latency, bandwidth; + + public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) { + this.connectionTime = connectionTime; + this.latency = latency; + this.bandwidth = bandwidth; + } + + @Override + protected void doStart() throws IOException { + this.serverSocketChannel = ServerSocketChannel.open(); + this.serverSocketChannel.socket().setSoTimeout(this.soTimeout); + if (this.connectionTime != 0 || this.latency != 0 || this.bandwidth != 0) { + this.serverSocketChannel.socket().setPerformancePreferences(this.connectionTime, this.latency, + this.bandwidth); + } + this.serverSocketChannel.configureBlocking(false); + + if (this.socketOptions.get(StandardSocketOption.SO_REUSEADDR) != null) { + this.serverSocketChannel.socket().setReuseAddress(StandardSocketOption.SO_REUSEADDR.type() + .cast(this.socketOptions.get(StandardSocketOption.SO_REUSEADDR))); + } + if (this.socketOptions.get(StandardSocketOption.SO_RCVBUF) != null) { + this.serverSocketChannel.socket().setReceiveBufferSize(StandardSocketOption.SO_RCVBUF.type() + .cast(this.socketOptions.get(StandardSocketOption.SO_RCVBUF))); + + } + if (this.localSocketAddress != null) { + this.serverSocketChannel.socket().bind(this.localSocketAddress, this.backlog); + } else { + this.serverSocketChannel.socket().bind(new InetSocketAddress("localhost", 0), this.backlog); + } + setLocalSocketAddress( + (InetSocketAddress) this.serverSocketChannel.socket().getLocalSocketAddress()); + this.selectorManager.registerChannel(this.serverSocketChannel, SelectionKey.OP_ACCEPT, null); + } + + @Override + public void onAccept(SelectionKey selectionKey) throws IOException { + // �������رգ�ȡ������ + if (!this.serverSocketChannel.isOpen()) { + selectionKey.cancel(); + return; + } + SocketChannel sc = null; + try { + sc = this.serverSocketChannel.accept(); + if (sc != null) { + configureSocketChannel(sc); + Session session = buildSession(sc); + // enable read + this.selectorManager.registerSession(session, EventType.ENABLE_READ); + session.start(); + super.onAccept(selectionKey); // for statistics + } else { + log.debug("Accept fail"); + } + } catch (IOException e) { + closeAcceptChannel(selectionKey, sc); + log.error("Accept connection error", e); + notifyException(e); + } + } + + /** + * + * @param sk + * @param sc + * @throws IOException + * @throws SocketException + */ + private void closeAcceptChannel(SelectionKey sk, SocketChannel sc) + throws IOException, SocketException { + if (sk != null) { + sk.cancel(); + } + if (sc != null) { + sc.socket().setSoLinger(true, 0); // await TIME_WAIT status + sc.socket().shutdownOutput(); + sc.close(); + } + } + + public void closeChannel(Selector selector) throws IOException { + if (this.serverSocketChannel != null) { + this.serverSocketChannel.close(); + } + } + + public void unbind() throws IOException { + stop(); + } + +} diff --git a/src/main/java/com/google/code/yanf4j/nio/impl/AbstractNioSession.java b/src/main/java/com/google/code/yanf4j/nio/impl/AbstractNioSession.java index 48138d21b..12daec2b9 100644 --- a/src/main/java/com/google/code/yanf4j/nio/impl/AbstractNioSession.java +++ b/src/main/java/com/google/code/yanf4j/nio/impl/AbstractNioSession.java @@ -10,7 +10,6 @@ import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.nio.channels.WritableByteChannel; - import com.google.code.yanf4j.buffer.IoBuffer; import com.google.code.yanf4j.core.EventType; import com.google.code.yanf4j.core.WriteMessage; @@ -25,334 +24,320 @@ * @author dennis * */ -public abstract class AbstractNioSession extends AbstractSession - implements - NioSession { +public abstract class AbstractNioSession extends AbstractSession implements NioSession { - public SelectableChannel channel() { - return selectableChannel; - } + public SelectableChannel channel() { + return selectableChannel; + } - protected SelectorManager selectorManager; - protected SelectableChannel selectableChannel; + protected SelectorManager selectorManager; + protected SelectableChannel selectableChannel; - public AbstractNioSession(NioSessionConfig sessionConfig) { - super(sessionConfig); - selectorManager = sessionConfig.selectorManager; - selectableChannel = sessionConfig.selectableChannel; - } + public AbstractNioSession(NioSessionConfig sessionConfig) { + super(sessionConfig); + selectorManager = sessionConfig.selectorManager; + selectableChannel = sessionConfig.selectableChannel; + } - public final void enableRead(Selector selector) { - SelectionKey key = selectableChannel.keyFor(selector); - if (key != null && key.isValid()) { - interestRead(key); - } else { - try { - selectableChannel.register(selector, SelectionKey.OP_READ, - this); - } catch (ClosedChannelException e) { - // ignore - } catch (CancelledKeyException e) { - // ignore - } - } - } + public final void enableRead(Selector selector) { + SelectionKey key = selectableChannel.keyFor(selector); + if (key != null && key.isValid()) { + interestRead(key); + } else { + try { + selectableChannel.register(selector, SelectionKey.OP_READ, this); + } catch (ClosedChannelException e) { + // ignore + } catch (CancelledKeyException e) { + // ignore + } + } + } - private void interestRead(SelectionKey key) { - if (key.attachment() == null) { - key.attach(this); - } - key.interestOps(key.interestOps() | SelectionKey.OP_READ); - } + private void interestRead(SelectionKey key) { + if (key.attachment() == null) { + key.attach(this); + } + key.interestOps(key.interestOps() | SelectionKey.OP_READ); + } - @Override - protected void start0() { - registerSession(); - } + @Override + protected void start0() { + registerSession(); + } - public InetAddress getLocalAddress() { - return ((SocketChannel) selectableChannel).socket().getLocalAddress(); - } + public InetAddress getLocalAddress() { + return ((SocketChannel) selectableChannel).socket().getLocalAddress(); + } - protected abstract Object writeToChannel(WriteMessage msg) - throws ClosedChannelException, IOException; + protected abstract Object writeToChannel(WriteMessage msg) + throws ClosedChannelException, IOException; - protected void onWrite(SelectionKey key) { - boolean isLockedByMe = false; - if (currentMessage.get() == null) { - // get next message - WriteMessage nextMessage = writeQueue.peek(); - if (nextMessage != null && writeLock.tryLock()) { - if (!writeQueue.isEmpty() - && currentMessage.compareAndSet(null, nextMessage)) { - writeQueue.remove(); - } - } else { - return; - } - } else if (!writeLock.tryLock()) { - return; - } + protected void onWrite(SelectionKey key) { + boolean isLockedByMe = false; + if (currentMessage.get() == null) { + // get next message + WriteMessage nextMessage = writeQueue.peek(); + if (nextMessage != null && writeLock.tryLock()) { + if (!writeQueue.isEmpty() && currentMessage.compareAndSet(null, nextMessage)) { + writeQueue.remove(); + } + } else { + return; + } + } else if (!writeLock.tryLock()) { + return; + } - isLockedByMe = true; - WriteMessage currentMessage = null; + isLockedByMe = true; + WriteMessage currentMessage = null; - final long maxWritten = readBuffer.capacity() - + readBuffer.capacity() >>> 1; - try { - long written = 0; - while (this.currentMessage.get() != null) { - currentMessage = this.currentMessage.get(); - currentMessage = preprocessWriteMessage(currentMessage); - this.currentMessage.set(currentMessage); - long before = this.currentMessage.get().getWriteBuffer() - .remaining(); - Object writeResult = null; + final long maxWritten = readBuffer.capacity() + readBuffer.capacity() >>> 1; + try { + long written = 0; + while (this.currentMessage.get() != null) { + currentMessage = this.currentMessage.get(); + currentMessage = preprocessWriteMessage(currentMessage); + this.currentMessage.set(currentMessage); + long before = this.currentMessage.get().getWriteBuffer().remaining(); + Object writeResult = null; - if (written < maxWritten) { - writeResult = writeToChannel(currentMessage); - written += this.currentMessage.get().getWriteBuffer() - .remaining() - before; - } else { - // wait for next time to write - } - // write complete - if (writeResult != null) { - this.currentMessage.set(writeQueue.poll()); - handler.onMessageSent(this, currentMessage.getMessage()); - // try to get next message - if (this.currentMessage.get() == null) { - if (isLockedByMe) { - isLockedByMe = false; - writeLock.unlock(); - } - // get next message - WriteMessage nextMessage = writeQueue.peek(); - if (nextMessage != null && writeLock.tryLock()) { - isLockedByMe = true; - if (!writeQueue.isEmpty() && this.currentMessage - .compareAndSet(null, nextMessage)) { - writeQueue.remove(); - } - continue; - } else { - break; - } - } - } else { - // does't write complete - if (isLockedByMe) { - isLockedByMe = false; - writeLock.unlock(); - } - // register OP_WRITE event - selectorManager.registerSession(this, - EventType.ENABLE_WRITE); - break; - } - } - } catch (IOException e) { - handler.onExceptionCaught(this, e); - if (currentMessage != null - && currentMessage.getWriteFuture() != null) { - currentMessage.getWriteFuture().failure(e); - } - if (isLockedByMe) { - isLockedByMe = false; - writeLock.unlock(); - } - close(); - } finally { - if (isLockedByMe) { - writeLock.unlock(); - } - } - } + if (written < maxWritten) { + writeResult = writeToChannel(currentMessage); + written += this.currentMessage.get().getWriteBuffer().remaining() - before; + } else { + // wait for next time to write + } + // write complete + if (writeResult != null) { + this.currentMessage.set(writeQueue.poll()); + handler.onMessageSent(this, currentMessage.getMessage()); + // try to get next message + if (this.currentMessage.get() == null) { + if (isLockedByMe) { + isLockedByMe = false; + writeLock.unlock(); + } + // get next message + WriteMessage nextMessage = writeQueue.peek(); + if (nextMessage != null && writeLock.tryLock()) { + isLockedByMe = true; + if (!writeQueue.isEmpty() && this.currentMessage.compareAndSet(null, nextMessage)) { + writeQueue.remove(); + } + continue; + } else { + break; + } + } + } else { + // does't write complete + if (isLockedByMe) { + isLockedByMe = false; + writeLock.unlock(); + } + // register OP_WRITE event + selectorManager.registerSession(this, EventType.ENABLE_WRITE); + break; + } + } + } catch (IOException e) { + handler.onExceptionCaught(this, e); + if (currentMessage != null && currentMessage.getWriteFuture() != null) { + currentMessage.getWriteFuture().failure(e); + } + if (isLockedByMe) { + isLockedByMe = false; + writeLock.unlock(); + } + close(); + } finally { + if (isLockedByMe) { + writeLock.unlock(); + } + } + } - public final void enableWrite(Selector selector) { - SelectionKey key = selectableChannel.keyFor(selector); - if (key != null && key.isValid()) { - interestWrite(key); - } else { - try { - selectableChannel.register(selector, SelectionKey.OP_WRITE, - this); - } catch (ClosedChannelException e) { - // ignore - } catch (CancelledKeyException e) { - // ignore - } - } - } + public final void enableWrite(Selector selector) { + SelectionKey key = selectableChannel.keyFor(selector); + if (key != null && key.isValid()) { + interestWrite(key); + } else { + try { + selectableChannel.register(selector, SelectionKey.OP_WRITE, this); + } catch (ClosedChannelException e) { + // ignore + } catch (CancelledKeyException e) { + // ignore + } + } + } - private void interestWrite(SelectionKey key) { - if (key.attachment() == null) { - key.attach(this); - } - key.interestOps(key.interestOps() | SelectionKey.OP_WRITE); - } + private void interestWrite(SelectionKey key) { + if (key.attachment() == null) { + key.attach(this); + } + key.interestOps(key.interestOps() | SelectionKey.OP_WRITE); + } - protected void onRead(SelectionKey key) { - readFromBuffer(); - } + protected void onRead(SelectionKey key) { + readFromBuffer(); + } - protected abstract void readFromBuffer(); + protected abstract void readFromBuffer(); - @Override - protected void closeChannel() throws IOException { - flush0(); - unregisterSession(); - unregisterChannel(); - } + @Override + protected void closeChannel() throws IOException { + flush0(); + unregisterSession(); + unregisterChannel(); + } - protected final void unregisterChannel() throws IOException { - writeLock.lock(); - try { - if (getAttribute(SelectorManager.REACTOR_ATTRIBUTE) != null) { - ((Reactor) getAttribute(SelectorManager.REACTOR_ATTRIBUTE)) - .unregisterChannel(selectableChannel); - } - if (selectableChannel.isOpen()) { - selectableChannel.close(); - } - } finally { - writeLock.unlock(); - } - } + protected final void unregisterChannel() throws IOException { + writeLock.lock(); + try { + if (getAttribute(SelectorManager.REACTOR_ATTRIBUTE) != null) { + ((Reactor) getAttribute(SelectorManager.REACTOR_ATTRIBUTE)) + .unregisterChannel(selectableChannel); + } + if (selectableChannel.isOpen()) { + selectableChannel.close(); + } + } finally { + writeLock.unlock(); + } + } - protected final void registerSession() { - selectorManager.registerSession(this, EventType.REGISTER); - } + protected final void registerSession() { + selectorManager.registerSession(this, EventType.REGISTER); + } - protected void unregisterSession() { - selectorManager.registerSession(this, EventType.UNREGISTER); - } + protected void unregisterSession() { + selectorManager.registerSession(this, EventType.UNREGISTER); + } - @Override - public void writeFromUserCode(WriteMessage message) { - if (schduleWriteMessage(message)) { - return; - } - onWrite(null); - } + @Override + public void writeFromUserCode(WriteMessage message) { + if (schduleWriteMessage(message)) { + return; + } + onWrite(null); + } - protected boolean schduleWriteMessage(WriteMessage writeMessage) { - boolean offered = writeQueue.offer(writeMessage); - assert offered; - final Reactor reactor = selectorManager.getReactorFromSession(this); - if (Thread.currentThread() != reactor) { - selectorManager.registerSession(this, EventType.ENABLE_WRITE); - return true; - } - return false; - } + protected boolean schduleWriteMessage(WriteMessage writeMessage) { + boolean offered = writeQueue.offer(writeMessage); + assert offered; + final Reactor reactor = selectorManager.getReactorFromSession(this); + if (Thread.currentThread() != reactor) { + selectorManager.registerSession(this, EventType.ENABLE_WRITE); + return true; + } + return false; + } - public void flush() { - if (isClosed()) { - return; - } - flush0(); - } + public void flush() { + if (isClosed()) { + return; + } + flush0(); + } - protected final void flush0() { - SelectionKey tmpKey = null; - Selector writeSelector = null; - int attempts = 0; - try { - while (true) { - if (writeSelector == null) { - writeSelector = SelectorFactory.getSelector(); - if (writeSelector == null) { - return; - } - tmpKey = selectableChannel.register(writeSelector, - SelectionKey.OP_WRITE); - } - if (writeSelector.select(1000) == 0) { - attempts++; - if (attempts > 2) { - return; - } - } else { - break; - } - } - onWrite(selectableChannel.keyFor(writeSelector)); - } catch (ClosedChannelException cce) { - onException(cce); - log.error("Flush error", cce); - close(); - } catch (IOException ioe) { - onException(ioe); - log.error("Flush error", ioe); - close(); - } finally { - if (tmpKey != null) { - // Cancel the key. - tmpKey.cancel(); - tmpKey = null; - } - if (writeSelector != null) { - try { - writeSelector.selectNow(); - } catch (IOException e) { - log.error("Temp selector selectNow error", e); - } - // return selector - SelectorFactory.returnSelector(writeSelector); - } - } - } + protected final void flush0() { + SelectionKey tmpKey = null; + Selector writeSelector = null; + int attempts = 0; + try { + while (true) { + if (writeSelector == null) { + writeSelector = SelectorFactory.getSelector(); + if (writeSelector == null) { + return; + } + tmpKey = selectableChannel.register(writeSelector, SelectionKey.OP_WRITE); + } + if (writeSelector.select(1000) == 0) { + attempts++; + if (attempts > 2) { + return; + } + } else { + break; + } + } + onWrite(selectableChannel.keyFor(writeSelector)); + } catch (ClosedChannelException cce) { + onException(cce); + log.error("Flush error", cce); + close(); + } catch (IOException ioe) { + onException(ioe); + log.error("Flush error", ioe); + close(); + } finally { + if (tmpKey != null) { + // Cancel the key. + tmpKey.cancel(); + tmpKey = null; + } + if (writeSelector != null) { + try { + writeSelector.selectNow(); + } catch (IOException e) { + log.error("Temp selector selectNow error", e); + } + // return selector + SelectorFactory.returnSelector(writeSelector); + } + } + } - protected final long doRealWrite(SelectableChannel channel, IoBuffer buffer) - throws IOException { - if (log.isDebugEnabled()) { - StringBuffer bufMsg = new StringBuffer("send buffers:\n[\n"); - final ByteBuffer buff = buffer.buf(); - bufMsg.append(" buffer:position=").append(buff.position()) - .append(",limit=").append(buff.limit()).append(",capacity=") - .append(buff.capacity()).append("\n"); + protected final long doRealWrite(SelectableChannel channel, IoBuffer buffer) throws IOException { + if (log.isDebugEnabled()) { + StringBuffer bufMsg = new StringBuffer("send buffers:\n[\n"); + final ByteBuffer buff = buffer.buf(); + bufMsg.append(" buffer:position=").append(buff.position()).append(",limit=") + .append(buff.limit()).append(",capacity=").append(buff.capacity()).append("\n"); - bufMsg.append("]"); - log.debug(bufMsg.toString()); - } - return ((WritableByteChannel) channel).write(buffer.buf()); - } + bufMsg.append("]"); + log.debug(bufMsg.toString()); + } + return ((WritableByteChannel) channel).write(buffer.buf()); + } - /** - * �ɷ�IO�¼� - */ - public final void onEvent(EventType event, Selector selector) { - if (isClosed()) { - return; - } - SelectionKey key = selectableChannel.keyFor(selector); + /** + * �ɷ�IO�¼� + */ + public final void onEvent(EventType event, Selector selector) { + if (isClosed()) { + return; + } + SelectionKey key = selectableChannel.keyFor(selector); - switch (event) { - case EXPIRED : - onExpired(); - break; - case WRITEABLE : - onWrite(key); - break; - case READABLE : - onRead(key); - break; - case ENABLE_WRITE : - enableWrite(selector); - break; - case ENABLE_READ : - enableRead(selector); - break; - case IDLE : - onIdle(); - break; - case CONNECTED : - onConnected(); - break; - default : - log.error("Unknown event:" + event.name()); - break; - } - } + switch (event) { + case EXPIRED: + onExpired(); + break; + case WRITEABLE: + onWrite(key); + break; + case READABLE: + onRead(key); + break; + case ENABLE_WRITE: + enableWrite(selector); + break; + case ENABLE_READ: + enableRead(selector); + break; + case IDLE: + onIdle(); + break; + case CONNECTED: + onConnected(); + break; + default: + log.error("Unknown event:" + event.name()); + break; + } + } } diff --git a/src/main/java/com/google/code/yanf4j/nio/impl/NioController.java b/src/main/java/com/google/code/yanf4j/nio/impl/NioController.java index 9a052625f..099d22b93 100644 --- a/src/main/java/com/google/code/yanf4j/nio/impl/NioController.java +++ b/src/main/java/com/google/code/yanf4j/nio/impl/NioController.java @@ -1,13 +1,10 @@ /** - *Copyright [2009-2010] [dennis zhuang] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang] Licensed 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 com.google.code.yanf4j.nio.impl; @@ -16,7 +13,6 @@ import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; import java.util.Queue; - import com.google.code.yanf4j.config.Configuration; import com.google.code.yanf4j.core.CodecFactory; import com.google.code.yanf4j.core.Handler; @@ -33,205 +29,198 @@ * @author dennis * */ -public abstract class NioController extends AbstractController - implements - SelectionKeyHandler { - - protected SelectorManager selectorManager; - - /** - * Reactor count - */ - protected int selectorPoolSize = SystemUtils.getSystemThreadCount(); - - /** - * @see setSelectorPoolSize - * @return - */ - public int getSelectorPoolSize() { - return this.selectorPoolSize; - } - - public void setSelectorPoolSize(int selectorPoolSize) { - if (isStarted()) { - throw new IllegalStateException("Controller has been started"); - } - this.selectorPoolSize = selectorPoolSize; - } - - public NioController() { - super(); - } - - public NioController(Configuration configuration, - CodecFactory codecFactory) { - super(configuration, codecFactory); - } - - public NioController(Configuration configuration, Handler handler, - CodecFactory codecFactory) { - super(configuration, handler, codecFactory); - } - - public NioController(Configuration configuration) { - super(configuration); - } - - /** - * Write task - * - * @author dennis - * - */ - private final class WriteTask implements Runnable { - private final SelectionKey key; - - private WriteTask(SelectionKey key) { - this.key = key; - } - - public final void run() { - dispatchWriteEvent(this.key); - } - } - - /** - * Read task - * - * @author dennis - * - */ - private final class ReadTask implements Runnable { - private final SelectionKey key; - - private ReadTask(SelectionKey key) { - this.key = key; - } - - public final void run() { - dispatchReadEvent(this.key); - } - } - - public final SelectorManager getSelectorManager() { - return this.selectorManager; - } - - @Override - protected void start0() throws IOException { - try { - initialSelectorManager(); - doStart(); - } catch (IOException e) { - log.error("Start server error", e); - notifyException(e); - stop(); - throw e; - } - - } - - /** - * Start selector manager - * - * @throws IOException - */ - protected void initialSelectorManager() throws IOException { - if (this.selectorManager == null) { - this.selectorManager = new SelectorManager(this.selectorPoolSize, - this, this.configuration); - this.selectorManager.start(); - } - } - - /** - * Inner startup - * - * @throws IOException - */ - protected abstract void doStart() throws IOException; - - /** - * Read event occured - */ - public void onRead(SelectionKey key) { - if (this.readEventDispatcher == null) { - dispatchReadEvent(key); - } else { - this.readEventDispatcher.dispatch(new ReadTask(key)); - } - } - - /** - * Writable event occured - */ - public void onWrite(final SelectionKey key) { - if (this.writeEventDispatcher == null) { - dispatchWriteEvent(key); - } else { - this.writeEventDispatcher.dispatch(new WriteTask(key)); - } - } - - /** - * Cancel selection key - */ - public void closeSelectionKey(SelectionKey key) { - if (key.attachment() instanceof Session) { - Session session = (Session) key.attachment(); - if (session != null) { - session.close(); - } - } - } - - /** - * Dispatch read event - * - * @param key - * @return - */ - protected abstract void dispatchReadEvent(final SelectionKey key); - - /** - * Dispatch write event - * - * @param key - * @return - */ - protected abstract void dispatchWriteEvent(final SelectionKey key); - - @Override - protected void stop0() throws IOException { - if (this.selectorManager == null || !this.selectorManager.isStarted()) { - return; - } - this.selectorManager.stop(); - } - - public synchronized void bind(int port) throws IOException { - if (isStarted()) { - throw new IllegalStateException( - "Server has been bind to " + getLocalSocketAddress()); - } - bind(new InetSocketAddress(port)); - } - - /** - * Build nio session config - * - * @param sc - * @param queue - * @return - */ - protected final NioSessionConfig buildSessionConfig(SelectableChannel sc, - Queue queue) { - final NioSessionConfig sessionConfig = new NioSessionConfig(sc, - getHandler(), this.selectorManager, getCodecFactory(), - getStatistics(), queue, this.dispatchMessageDispatcher, - isHandleReadWriteConcurrently(), this.sessionTimeout, - this.configuration.getSessionIdleTimeout()); - return sessionConfig; - } +public abstract class NioController extends AbstractController implements SelectionKeyHandler { + + protected SelectorManager selectorManager; + + /** + * Reactor count + */ + protected int selectorPoolSize = SystemUtils.getSystemThreadCount(); + + /** + * @see setSelectorPoolSize + * @return + */ + public int getSelectorPoolSize() { + return this.selectorPoolSize; + } + + public void setSelectorPoolSize(int selectorPoolSize) { + if (isStarted()) { + throw new IllegalStateException("Controller has been started"); + } + this.selectorPoolSize = selectorPoolSize; + } + + public NioController() { + super(); + } + + public NioController(Configuration configuration, CodecFactory codecFactory) { + super(configuration, codecFactory); + } + + public NioController(Configuration configuration, Handler handler, CodecFactory codecFactory) { + super(configuration, handler, codecFactory); + } + + public NioController(Configuration configuration) { + super(configuration); + } + + /** + * Write task + * + * @author dennis + * + */ + private final class WriteTask implements Runnable { + private final SelectionKey key; + + private WriteTask(SelectionKey key) { + this.key = key; + } + + public final void run() { + dispatchWriteEvent(this.key); + } + } + + /** + * Read task + * + * @author dennis + * + */ + private final class ReadTask implements Runnable { + private final SelectionKey key; + + private ReadTask(SelectionKey key) { + this.key = key; + } + + public final void run() { + dispatchReadEvent(this.key); + } + } + + public final SelectorManager getSelectorManager() { + return this.selectorManager; + } + + @Override + protected void start0() throws IOException { + try { + initialSelectorManager(); + doStart(); + } catch (IOException e) { + log.error("Start server error", e); + notifyException(e); + stop(); + throw e; + } + + } + + /** + * Start selector manager + * + * @throws IOException + */ + protected void initialSelectorManager() throws IOException { + if (this.selectorManager == null) { + this.selectorManager = new SelectorManager(this.selectorPoolSize, this, this.configuration); + this.selectorManager.start(); + } + } + + /** + * Inner startup + * + * @throws IOException + */ + protected abstract void doStart() throws IOException; + + /** + * Read event occured + */ + public void onRead(SelectionKey key) { + if (this.readEventDispatcher == null) { + dispatchReadEvent(key); + } else { + this.readEventDispatcher.dispatch(new ReadTask(key)); + } + } + + /** + * Writable event occured + */ + public void onWrite(final SelectionKey key) { + if (this.writeEventDispatcher == null) { + dispatchWriteEvent(key); + } else { + this.writeEventDispatcher.dispatch(new WriteTask(key)); + } + } + + /** + * Cancel selection key + */ + public void closeSelectionKey(SelectionKey key) { + if (key.attachment() instanceof Session) { + Session session = (Session) key.attachment(); + if (session != null) { + session.close(); + } + } + } + + /** + * Dispatch read event + * + * @param key + * @return + */ + protected abstract void dispatchReadEvent(final SelectionKey key); + + /** + * Dispatch write event + * + * @param key + * @return + */ + protected abstract void dispatchWriteEvent(final SelectionKey key); + + @Override + protected void stop0() throws IOException { + if (this.selectorManager == null || !this.selectorManager.isStarted()) { + return; + } + this.selectorManager.stop(); + } + + public synchronized void bind(int port) throws IOException { + if (isStarted()) { + throw new IllegalStateException("Server has been bind to " + getLocalSocketAddress()); + } + bind(new InetSocketAddress(port)); + } + + /** + * Build nio session config + * + * @param sc + * @param queue + * @return + */ + protected final NioSessionConfig buildSessionConfig(SelectableChannel sc, + Queue queue) { + final NioSessionConfig sessionConfig = + new NioSessionConfig(sc, getHandler(), this.selectorManager, getCodecFactory(), + getStatistics(), queue, this.dispatchMessageDispatcher, isHandleReadWriteConcurrently(), + this.sessionTimeout, this.configuration.getSessionIdleTimeout()); + return sessionConfig; + } } diff --git a/src/main/java/com/google/code/yanf4j/nio/impl/NioTCPSession.java b/src/main/java/com/google/code/yanf4j/nio/impl/NioTCPSession.java index 55398e647..b6a9072f9 100644 --- a/src/main/java/com/google/code/yanf4j/nio/impl/NioTCPSession.java +++ b/src/main/java/com/google/code/yanf4j/nio/impl/NioTCPSession.java @@ -1,15 +1,12 @@ package com.google.code.yanf4j.nio.impl; /** - *Copyright [2008-2009] [dennis zhuang] - *Licensed 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 + * Copyright [2008-2009] [dennis zhuang] Licensed 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 */ import java.io.IOException; import java.net.InetSocketAddress; @@ -21,7 +18,6 @@ import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.util.concurrent.Future; - import com.google.code.yanf4j.buffer.IoBuffer; import com.google.code.yanf4j.config.Configuration; import com.google.code.yanf4j.core.EventType; @@ -39,314 +35,293 @@ * */ public class NioTCPSession extends AbstractNioSession { - private InetSocketAddress remoteAddress; + private InetSocketAddress remoteAddress; - @Override - public final boolean isExpired() { - if (log.isDebugEnabled()) { - log.debug("sessionTimeout=" + this.sessionTimeout - + ",this.timestamp=" + this.lastOperationTimeStamp.get() - + ",current=" + System.currentTimeMillis()); - } - return this.sessionTimeout <= 0 - ? false - : System.currentTimeMillis() - this.lastOperationTimeStamp - .get() >= this.sessionTimeout; - } + @Override + public final boolean isExpired() { + if (log.isDebugEnabled()) { + log.debug("sessionTimeout=" + this.sessionTimeout + ",this.timestamp=" + + this.lastOperationTimeStamp.get() + ",current=" + System.currentTimeMillis()); + } + return this.sessionTimeout <= 0 ? false + : System.currentTimeMillis() - this.lastOperationTimeStamp.get() >= this.sessionTimeout; + } - public NioTCPSession(NioSessionConfig sessionConfig, - int readRecvBufferSize) { - super(sessionConfig); - if (this.selectableChannel != null - && this.getRemoteSocketAddress() != null) { - this.loopback = this.getRemoteSocketAddress().getAddress() - .isLoopbackAddress(); - } - this.setReadBuffer(IoBuffer.allocate(readRecvBufferSize)); - this.onCreated(); - } + public NioTCPSession(NioSessionConfig sessionConfig, int readRecvBufferSize) { + super(sessionConfig); + if (this.selectableChannel != null && this.getRemoteSocketAddress() != null) { + this.loopback = this.getRemoteSocketAddress().getAddress().isLoopbackAddress(); + } + this.setReadBuffer(IoBuffer.allocate(readRecvBufferSize)); + this.onCreated(); + } - @Override - protected Object writeToChannel(WriteMessage message) throws IOException { - if (message.getWriteFuture() != null && !message.isWriting() - && message.getWriteFuture().isCancelled()) { - return message.getMessage(); - } - if (message.getWriteBuffer() == null) { - if (message.getWriteFuture() != null) { - message.getWriteFuture().setResult(Boolean.TRUE); - } - return message.getMessage(); - } - IoBuffer writeBuffer = message.getWriteBuffer(); - // begin writing - message.writing(); - if (this.useBlockingWrite) { - return this.blockingWrite(this.selectableChannel, message, - writeBuffer); - } else { - while (true) { - long n = this.doRealWrite(this.selectableChannel, writeBuffer); - if (n > 0) { - this.statistics.statisticsWrite(n); - this.scheduleWritenBytes.addAndGet(0 - n); - } - if (writeBuffer == null || !writeBuffer.hasRemaining()) { - if (message.getWriteFuture() != null) { - message.getWriteFuture().setResult(Boolean.TRUE); - } - return message.getMessage(); - } else if (n == 0) { - // have more data, but the buffer is full, - // wait next time to write - return null; - } - } - } + @Override + protected Object writeToChannel(WriteMessage message) throws IOException { + if (message.getWriteFuture() != null && !message.isWriting() + && message.getWriteFuture().isCancelled()) { + return message.getMessage(); + } + if (message.getWriteBuffer() == null) { + if (message.getWriteFuture() != null) { + message.getWriteFuture().setResult(Boolean.TRUE); + } + return message.getMessage(); + } + IoBuffer writeBuffer = message.getWriteBuffer(); + // begin writing + message.writing(); + if (this.useBlockingWrite) { + return this.blockingWrite(this.selectableChannel, message, writeBuffer); + } else { + while (true) { + long n = this.doRealWrite(this.selectableChannel, writeBuffer); + if (n > 0) { + this.statistics.statisticsWrite(n); + this.scheduleWritenBytes.addAndGet(0 - n); + } + if (writeBuffer == null || !writeBuffer.hasRemaining()) { + if (message.getWriteFuture() != null) { + message.getWriteFuture().setResult(Boolean.TRUE); + } + return message.getMessage(); + } else if (n == 0) { + // have more data, but the buffer is full, + // wait next time to write + return null; + } + } + } - } + } - public InetSocketAddress getRemoteSocketAddress() { - if (this.remoteAddress == null) { - this.remoteAddress = (InetSocketAddress) ((SocketChannel) this.selectableChannel) - .socket().getRemoteSocketAddress(); - } - return this.remoteAddress; - } + public InetSocketAddress getRemoteSocketAddress() { + if (this.remoteAddress == null) { + this.remoteAddress = (InetSocketAddress) ((SocketChannel) this.selectableChannel).socket() + .getRemoteSocketAddress(); + } + return this.remoteAddress; + } - /** - * Blocking write using temp selector - * - * @param channel - * @param message - * @param writeBuffer - * @return - * @throws IOException - * @throws ClosedChannelException - */ - protected final Object blockingWrite(SelectableChannel channel, - WriteMessage message, IoBuffer writeBuffer) - throws IOException, ClosedChannelException { - SelectionKey tmpKey = null; - Selector writeSelector = null; - int attempts = 0; - int bytesProduced = 0; - try { - while (writeBuffer.hasRemaining()) { - long len = this.doRealWrite(channel, writeBuffer); - if (len > 0) { - attempts = 0; - bytesProduced += len; - this.statistics.statisticsWrite(len); - } else { - attempts++; - if (writeSelector == null) { - writeSelector = SelectorFactory.getSelector(); - if (writeSelector == null) { - // Continue using the main one. - continue; - } - tmpKey = channel.register(writeSelector, - SelectionKey.OP_WRITE); - } - if (writeSelector.select(1000) == 0) { - if (attempts > 2) { - throw new IOException("Client disconnected"); - } - } - } - } - if (!writeBuffer.hasRemaining() - && message.getWriteFuture() != null) { - message.getWriteFuture().setResult(Boolean.TRUE); - } - } finally { - if (tmpKey != null) { - tmpKey.cancel(); - tmpKey = null; - } - if (writeSelector != null) { - // Cancel the key. - writeSelector.selectNow(); - SelectorFactory.returnSelector(writeSelector); - } - } - this.scheduleWritenBytes.addAndGet(0 - bytesProduced); - return message.getMessage(); - } + /** + * Blocking write using temp selector + * + * @param channel + * @param message + * @param writeBuffer + * @return + * @throws IOException + * @throws ClosedChannelException + */ + protected final Object blockingWrite(SelectableChannel channel, WriteMessage message, + IoBuffer writeBuffer) throws IOException, ClosedChannelException { + SelectionKey tmpKey = null; + Selector writeSelector = null; + int attempts = 0; + int bytesProduced = 0; + try { + while (writeBuffer.hasRemaining()) { + long len = this.doRealWrite(channel, writeBuffer); + if (len > 0) { + attempts = 0; + bytesProduced += len; + this.statistics.statisticsWrite(len); + } else { + attempts++; + if (writeSelector == null) { + writeSelector = SelectorFactory.getSelector(); + if (writeSelector == null) { + // Continue using the main one. + continue; + } + tmpKey = channel.register(writeSelector, SelectionKey.OP_WRITE); + } + if (writeSelector.select(1000) == 0) { + if (attempts > 2) { + throw new IOException("Client disconnected"); + } + } + } + } + if (!writeBuffer.hasRemaining() && message.getWriteFuture() != null) { + message.getWriteFuture().setResult(Boolean.TRUE); + } + } finally { + if (tmpKey != null) { + tmpKey.cancel(); + tmpKey = null; + } + if (writeSelector != null) { + // Cancel the key. + writeSelector.selectNow(); + SelectorFactory.returnSelector(writeSelector); + } + } + this.scheduleWritenBytes.addAndGet(0 - bytesProduced); + return message.getMessage(); + } - @Override - protected WriteMessage wrapMessage(Object msg, - Future writeFuture) { - WriteMessage message = new WriteMessageImpl(msg, - (FutureImpl) writeFuture); - if (message.getWriteBuffer() == null) { - message.setWriteBuffer( - this.encoder.encode(message.getMessage(), this)); - } - return message; - } + @Override + protected WriteMessage wrapMessage(Object msg, Future writeFuture) { + WriteMessage message = new WriteMessageImpl(msg, (FutureImpl) writeFuture); + if (message.getWriteBuffer() == null) { + message.setWriteBuffer(this.encoder.encode(message.getMessage(), this)); + } + return message; + } - @Override - protected void readFromBuffer() { - if (!this.readBuffer.hasRemaining()) { - if (this.readBuffer - .capacity() < Configuration.MAX_READ_BUFFER_SIZE) { - this.readBuffer = IoBuffer.wrap(ByteBufferUtils - .increaseBufferCapatity(this.readBuffer.buf())); - } else { - // buffer's capacity is greater than maxium - return; - } - } - if (this.closed) { - return; - } - int n = -1; - int readCount = 0; - try { - while ((n = ((ReadableByteChannel) this.selectableChannel) - .read(this.readBuffer.buf())) > 0) { - readCount += n; - } - if (readCount > 0) { - decodeAndDispatch(); - } else if (readCount == 0 - && !((SocketChannel) this.selectableChannel).socket() - .isInputShutdown() - && this.useBlockingRead) { - n = this.blockingRead(); - if (n > 0) { - readCount += n; - } - } - if (n < 0) { // Connection closed - this.close(); - } else { - this.selectorManager.registerSession(this, - EventType.ENABLE_READ); - } - if (log.isDebugEnabled()) { - log.debug("read " + readCount + " bytes from channel"); - } - } catch (ClosedChannelException e) { - // ignore exception - this.close(); - } catch (Throwable e) { - this.onException(e); - this.close(); - } - } + @Override + protected void readFromBuffer() { + if (!this.readBuffer.hasRemaining()) { + if (this.readBuffer.capacity() < Configuration.MAX_READ_BUFFER_SIZE) { + this.readBuffer = + IoBuffer.wrap(ByteBufferUtils.increaseBufferCapatity(this.readBuffer.buf())); + } else { + // buffer's capacity is greater than maxium + return; + } + } + if (this.closed) { + return; + } + int n = -1; + int readCount = 0; + try { + while ((n = ((ReadableByteChannel) this.selectableChannel).read(this.readBuffer.buf())) > 0) { + readCount += n; + } + if (readCount > 0) { + decodeAndDispatch(); + } else if (readCount == 0 + && !((SocketChannel) this.selectableChannel).socket().isInputShutdown() + && this.useBlockingRead) { + n = this.blockingRead(); + if (n > 0) { + readCount += n; + } + } + if (n < 0) { // Connection closed + this.close(); + } else { + this.selectorManager.registerSession(this, EventType.ENABLE_READ); + } + if (log.isDebugEnabled()) { + log.debug("read " + readCount + " bytes from channel"); + } + } catch (ClosedChannelException e) { + // ignore exception + this.close(); + } catch (Throwable e) { + this.onException(e); + this.close(); + } + } - private void decodeAndDispatch() { - updateTimeStamp(); - this.readBuffer.flip(); - this.decode(); - this.readBuffer.compact(); - } + private void decodeAndDispatch() { + updateTimeStamp(); + this.readBuffer.flip(); + this.decode(); + this.readBuffer.compact(); + } - /** - * Blocking read using temp selector - * - * @return - * @throws ClosedChannelException - * @throws IOException - */ - protected final int blockingRead() - throws ClosedChannelException, IOException { - int n = 0; - int readCount = 0; - Selector readSelector = SelectorFactory.getSelector(); - SelectionKey tmpKey = null; - try { - if (this.selectableChannel.isOpen()) { - tmpKey = this.selectableChannel.register(readSelector, 0); - tmpKey.interestOps(tmpKey.interestOps() | SelectionKey.OP_READ); - int code = readSelector.select(500); - tmpKey.interestOps( - tmpKey.interestOps() & ~SelectionKey.OP_READ); - if (code > 0) { - do { - n = ((ReadableByteChannel) this.selectableChannel) - .read(this.readBuffer.buf()); - readCount += n; - if (log.isDebugEnabled()) { - log.debug("use temp selector read " + n + " bytes"); - } - } while (n > 0 && this.readBuffer.hasRemaining()); - if (readCount > 0) { - decodeAndDispatch(); - } - } - } - } finally { - if (tmpKey != null) { - tmpKey.cancel(); - tmpKey = null; - } - if (readSelector != null) { - // Cancel the key. - readSelector.selectNow(); - SelectorFactory.returnSelector(readSelector); - } - } - return readCount; - } + /** + * Blocking read using temp selector + * + * @return + * @throws ClosedChannelException + * @throws IOException + */ + protected final int blockingRead() throws ClosedChannelException, IOException { + int n = 0; + int readCount = 0; + Selector readSelector = SelectorFactory.getSelector(); + SelectionKey tmpKey = null; + try { + if (this.selectableChannel.isOpen()) { + tmpKey = this.selectableChannel.register(readSelector, 0); + tmpKey.interestOps(tmpKey.interestOps() | SelectionKey.OP_READ); + int code = readSelector.select(500); + tmpKey.interestOps(tmpKey.interestOps() & ~SelectionKey.OP_READ); + if (code > 0) { + do { + n = ((ReadableByteChannel) this.selectableChannel).read(this.readBuffer.buf()); + readCount += n; + if (log.isDebugEnabled()) { + log.debug("use temp selector read " + n + " bytes"); + } + } while (n > 0 && this.readBuffer.hasRemaining()); + if (readCount > 0) { + decodeAndDispatch(); + } + } + } + } finally { + if (tmpKey != null) { + tmpKey.cancel(); + tmpKey = null; + } + if (readSelector != null) { + // Cancel the key. + readSelector.selectNow(); + SelectorFactory.returnSelector(readSelector); + } + } + return readCount; + } - /** - * Decode buffer - */ - @Override - public void decode() { - Object message; - int size = this.readBuffer.remaining(); - while (this.readBuffer.hasRemaining()) { - try { - message = this.decoder.decode(this.readBuffer, this); - if (message == null) { - break; - } else { - if (this.statistics.isStatistics()) { - this.statistics.statisticsRead( - size - this.readBuffer.remaining()); - size = this.readBuffer.remaining(); - } - } - this.dispatchReceivedMessage(message); - } catch (Exception e) { - this.onException(e); - log.error("Decode error", e); - super.close(); - break; - } - } - } + /** + * Decode buffer + */ + @Override + public void decode() { + Object message; + int size = this.readBuffer.remaining(); + while (this.readBuffer.hasRemaining()) { + try { + message = this.decoder.decode(this.readBuffer, this); + if (message == null) { + break; + } else { + if (this.statistics.isStatistics()) { + this.statistics.statisticsRead(size - this.readBuffer.remaining()); + size = this.readBuffer.remaining(); + } + } + this.dispatchReceivedMessage(message); + } catch (Exception e) { + this.onException(e); + log.error("Decode error", e); + super.close(); + break; + } + } + } - public Socket socket() { - return ((SocketChannel) this.selectableChannel).socket(); - } + public Socket socket() { + return ((SocketChannel) this.selectableChannel).socket(); + } - @Override - protected final void closeChannel() throws IOException { - this.flush0(); - // try to close output first - Socket socket = ((SocketChannel) this.selectableChannel).socket(); - try { - if (!socket.isClosed() && !socket.isOutputShutdown()) { - socket.shutdownOutput(); - } - if (!socket.isClosed() && !socket.isInputShutdown()) { - socket.shutdownInput(); - } - } catch (Exception e) { - } - try { - socket.close(); - } catch (Exception e) { + @Override + protected final void closeChannel() throws IOException { + this.flush0(); + // try to close output first + Socket socket = ((SocketChannel) this.selectableChannel).socket(); + try { + if (!socket.isClosed() && !socket.isOutputShutdown()) { + socket.shutdownOutput(); + } + if (!socket.isClosed() && !socket.isInputShutdown()) { + socket.shutdownInput(); + } + } catch (Exception e) { + } + try { + socket.close(); + } catch (Exception e) { - } - this.unregisterSession(); - this.unregisterChannel(); - } + } + this.unregisterSession(); + this.unregisterChannel(); + } } diff --git a/src/main/java/com/google/code/yanf4j/nio/impl/Reactor.java b/src/main/java/com/google/code/yanf4j/nio/impl/Reactor.java index e67c561e7..05ae11126 100644 --- a/src/main/java/com/google/code/yanf4j/nio/impl/Reactor.java +++ b/src/main/java/com/google/code/yanf4j/nio/impl/Reactor.java @@ -20,10 +20,8 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import com.google.code.yanf4j.config.Configuration; import com.google.code.yanf4j.core.EventType; import com.google.code.yanf4j.core.Session; @@ -37,536 +35,510 @@ * */ public final class Reactor extends Thread { - /** - * JVM bug threshold - */ - public static final int JVMBUG_THRESHHOLD = Integer - .getInteger("com.googlecode.yanf4j.nio.JVMBUG_THRESHHOLD", 128); - public static final int JVMBUG_THRESHHOLD2 = JVMBUG_THRESHHOLD * 2; - public static final int JVMBUG_THRESHHOLD1 = (JVMBUG_THRESHHOLD2 - + JVMBUG_THRESHHOLD) / 2; - public static final int DEFAULT_WAIT = 1000; - - private static final Logger log = LoggerFactory.getLogger("remoting"); - - private boolean jvmBug0; - private boolean jvmBug1; - - private final int reactorIndex; - - private final SelectorManager selectorManager; - - private final AtomicInteger jvmBug = new AtomicInteger(0); - - private long lastJVMBug; - - private Selector selector; - - private final NioController controller; - - private final Configuration configuration; - - static public class PaddingAtomicBoolean extends AtomicBoolean { - - /** - * - */ - private static final long serialVersionUID = 5227571972657902891L; - public int p1; - public long p2, p3, p4, p5, p6, p7, p8; - - PaddingAtomicBoolean(boolean v) { - super(v); - } - } - - private final AtomicBoolean wakenUp = new PaddingAtomicBoolean(false); - - public static class RegisterEvent { - SelectableChannel channel; - int ops; - EventType eventType; - Object attachment; - Session session; - - public RegisterEvent(SelectableChannel channel, int ops, - Object attachment) { - super(); - this.channel = channel; - this.ops = ops; - this.attachment = attachment; - } - - public RegisterEvent(Session session, EventType eventType) { - super(); - this.session = session; - this.eventType = eventType; - } - } - - private Queue register; - - private final Lock gate = new ReentrantLock(); - - private int selectTries = 0; - - private long nextTimeout = 0; - - private long lastCheckTimestamp = 0L; - - Reactor(SelectorManager selectorManager, Configuration configuration, - int index) throws IOException { - super(); - reactorIndex = index; - this.register = (Queue) SystemUtils - .createTransferQueue(); - this.selectorManager = selectorManager; - controller = selectorManager.getController(); - selector = SystemUtils.openSelector(); - this.configuration = configuration; - setName("Xmemcached-Reactor-" + index); - setDaemon(true); - } - - public final Selector getSelector() { - return selector; - } - - public int getReactorIndex() { - return reactorIndex; - } - - @Override - public void run() { - selectorManager.notifyReady(); - while (selectorManager.isStarted() && selector.isOpen()) { - try { - beforeSelect(); - wakenUp.set(false); - long before = -1; - // Wether to look jvm bug - if (SystemUtils.isLinuxPlatform() - && !SystemUtils.isAfterJava6u4Version()) { - before = System.currentTimeMillis(); - } - long wait = DEFAULT_WAIT; - if (nextTimeout > 0) { - wait = nextTimeout; - } - int selected = selector.select(wait); - if (selected == 0) { - if (before != -1) { - lookJVMBug(before, selected, wait); - } - selectTries++; - // check timeout and idle - nextTimeout = checkSessionTimeout(); - continue; - } else { - selectTries = 0; - } - - } catch (ClosedSelectorException e) { - break; - } catch (IOException e) { - log.error("Reactor select error", e); - if (selector.isOpen()) { - continue; - } else { - break; - } - } - Set selectedKeys = selector.selectedKeys(); - gate.lock(); - try { - postSelect(selectedKeys, selector.keys()); - dispatchEvent(selectedKeys); - } finally { - gate.unlock(); - } - } - if (selector != null) { - if (selector.isOpen()) { - try { - controller.closeChannel(selector); - selector.close(); - } catch (IOException e) { - controller.notifyException(e); - log.error("stop reactor error", e); - } - } - } - - } - - /** - * Look jvm bug - * - * @param before - * @param selected - * @param wait - * @return - * @throws IOException - */ - private boolean lookJVMBug(long before, int selected, long wait) - throws IOException { - boolean seeing = false; - long now = System.currentTimeMillis(); - - if (JVMBUG_THRESHHOLD > 0 && selected == 0 && wait > JVMBUG_THRESHHOLD - && now - before < wait / 4 && !wakenUp.get() /* waken up */ - && !Thread.currentThread().isInterrupted()/* Interrupted */) { - jvmBug.incrementAndGet(); - if (jvmBug.get() >= JVMBUG_THRESHHOLD2) { - gate.lock(); - try { - lastJVMBug = now; - log.warn("JVM bug occured at " + new Date(lastJVMBug) - + ",http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6403933,reactIndex=" - + reactorIndex); - if (jvmBug1) { - log.debug( - "seeing JVM BUG(s) - recreating selector,reactIndex=" - + reactorIndex); - } else { - jvmBug1 = true; - log.info( - "seeing JVM BUG(s) - recreating selector,reactIndex=" - + reactorIndex); - } - seeing = true; - final Selector new_selector = SystemUtils.openSelector(); - - for (SelectionKey k : selector.keys()) { - if (!k.isValid() || k.interestOps() == 0) { - continue; - } - - final SelectableChannel channel = k.channel(); - final Object attachment = k.attachment(); - - channel.register(new_selector, k.interestOps(), - attachment); - } - - selector.close(); - selector = new_selector; - - } finally { - gate.unlock(); - } - jvmBug.set(0); - - } else if (jvmBug.get() == JVMBUG_THRESHHOLD - || jvmBug.get() == JVMBUG_THRESHHOLD1) { - if (jvmBug0) { - log.debug( - "seeing JVM BUG(s) - cancelling interestOps==0,reactIndex=" - + reactorIndex); - } else { - jvmBug0 = true; - log.info( - "seeing JVM BUG(s) - cancelling interestOps==0,reactIndex=" - + reactorIndex); - } - gate.lock(); - seeing = true; - try { - for (SelectionKey k : selector.keys()) { - if (k.isValid() && k.interestOps() == 0) { - k.cancel(); - } - } - } finally { - gate.unlock(); - } - } - } else { - jvmBug.set(0); - } - return seeing; - } - - /** - * Dispatch selected event - * - * @param selectedKeySet - */ - public final void dispatchEvent(Set selectedKeySet) { - Iterator it = selectedKeySet.iterator(); - boolean skipOpRead = false; - while (it.hasNext()) { - SelectionKey key = it.next(); - it.remove(); - if (!key.isValid()) { - if (key.attachment() != null) { - controller.closeSelectionKey(key); - } else { - key.cancel(); - } - continue; - } - try { - if (key.isValid() && key.isAcceptable()) { - controller.onAccept(key); - continue; - } - if (key.isValid() && (key.readyOps() - & SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE) { - // Remove write interest - key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE); - controller.onWrite(key); - if (!controller.isHandleReadWriteConcurrently()) { - skipOpRead = true; - } - } - if (!skipOpRead && key.isValid() && (key.readyOps() - & SelectionKey.OP_READ) == SelectionKey.OP_READ) { - key.interestOps(key.interestOps() & ~SelectionKey.OP_READ); - if (!controller.getStatistics().isReceiveOverFlow()) { - // Remove read interest - controller.onRead(key); - } else { - key.interestOps( - key.interestOps() | SelectionKey.OP_READ); - } - - } - if ((key.readyOps() - & SelectionKey.OP_CONNECT) == SelectionKey.OP_CONNECT) { - controller.onConnect(key); - } - - } catch (CancelledKeyException e) { - // ignore - } catch (RejectedExecutionException e) { - - if (key.attachment() instanceof AbstractNioSession) { - ((AbstractNioSession) key.attachment()).onException(e); - } - controller.notifyException(e); - if (selector.isOpen()) { - continue; - } else { - break; - } - } catch (Exception e) { - if (key.attachment() instanceof AbstractNioSession) { - ((AbstractNioSession) key.attachment()).onException(e); - } - controller.closeSelectionKey(key); - controller.notifyException(e); - log.error("Reactor dispatch events error", e); - if (selector.isOpen()) { - continue; - } else { - break; - } - } - } - } - - final void unregisterChannel(SelectableChannel channel) throws IOException { - Selector selector = this.selector; - if (selector != null) { - if (channel != null) { - SelectionKey key = channel.keyFor(selector); - if (key != null) { - key.cancel(); - } - } - } - wakeup(); - } - - /** - * Check session timeout or idle - * - * @return - */ - private final long checkSessionTimeout() { - long nextTimeout = 0; - if (configuration.getCheckSessionTimeoutInterval() > 0) { - gate.lock(); - try { - if (isNeedCheckSessionIdleTimeout()) { - nextTimeout = configuration - .getCheckSessionTimeoutInterval(); - for (SelectionKey key : selector.keys()) { - - if (key.attachment() != null) { - long n = checkExpiredIdle(key, - getSessionFromAttchment(key)); - nextTimeout = n < nextTimeout ? n : nextTimeout; - } - } - selectTries = 0; - lastCheckTimestamp = System.currentTimeMillis(); - } - } finally { - gate.unlock(); - } - } - return nextTimeout; - } - - private boolean isNeedCheckSessionIdleTimeout() { - return selectTries * 1000 >= configuration - .getCheckSessionTimeoutInterval() - || System.currentTimeMillis() - - this.lastCheckTimestamp >= configuration - .getCheckSessionTimeoutInterval(); - } - - private final Session getSessionFromAttchment(SelectionKey key) { - if (key.attachment() instanceof Session) { - return (Session) key.attachment(); - } - return null; - } - - public final void registerSession(Session session, EventType event) { - final Selector selector = this.selector; - if (isReactorThread() && selector != null) { - dispatchSessionEvent(session, event); - } else { - register.offer(new RegisterEvent(session, event)); - wakeup(); - } - } - - private final boolean isReactorThread() { - return Thread.currentThread() == this; - } - - final void beforeSelect() { - controller.checkStatisticsForRestart(); - processRegister(); - } - - private final void processRegister() { - RegisterEvent event = null; - while ((event = register.poll()) != null) { - if (event.session != null) { - dispatchSessionEvent(event.session, event.eventType); - } else { - registerChannelNow(event.channel, event.ops, event.attachment); - } - } - } - - Configuration getConfiguration() { - return configuration; - } - - private final void dispatchSessionEvent(Session session, EventType event) { - if (session.isClosed() && event != EventType.UNREGISTER) { - return; - } - switch (event) { - case REGISTER : - controller.registerSession(session); - break; - case UNREGISTER : - controller.unregisterSession(session); - break; - default : - ((NioSession) session).onEvent(event, selector); - break; - } - } - - public final void postSelect(Set selectedKeys, - Set allKeys) { - if (controller.getSessionTimeout() > 0 - || controller.getSessionIdleTimeout() > 0) { - if (isNeedCheckSessionIdleTimeout()) { - for (SelectionKey key : allKeys) { - if (!selectedKeys.contains(key)) { - if (key.attachment() != null) { - checkExpiredIdle(key, getSessionFromAttchment(key)); - } - } - } - lastCheckTimestamp = System.currentTimeMillis(); - } - } - } - - private long checkExpiredIdle(SelectionKey key, Session session) { - if (session == null) { - return 0; - } - long nextTimeout = 0; - boolean expired = false; - if (controller.getSessionTimeout() > 0) { - expired = checkExpired(key, session); - nextTimeout = controller.getSessionTimeout(); - } - if (controller.getSessionIdleTimeout() > 0 && !expired) { - checkIdle(session); - nextTimeout = controller.getSessionIdleTimeout(); - } - return nextTimeout; - } - - private final void checkIdle(Session session) { - if (controller.getSessionIdleTimeout() > 0) { - if (session.isIdle()) { - ((NioSession) session).onEvent(EventType.IDLE, selector); - } - } - } - - private final boolean checkExpired(SelectionKey key, Session session) { - if (session != null && session.isExpired()) { - ((NioSession) session).onEvent(EventType.EXPIRED, selector); - controller.closeSelectionKey(key); - return true; - } - return false; - } - - public final void registerChannel(SelectableChannel channel, int ops, - Object attachment) { - if (isReactorThread()) { - registerChannelNow(channel, ops, attachment); - } else { - register.offer(new RegisterEvent(channel, ops, attachment)); - wakeup(); - } - - } - - private void registerChannelNow(SelectableChannel channel, int ops, - Object attachment) { - if (channel.isOpen()) { - gate.lock(); - try { - channel.register(selector, ops, attachment); - - } catch (ClosedChannelException e) { - log.error("Register channel error", e); - controller.notifyException(e); - } finally { - gate.unlock(); - } - } - } - - final void wakeup() { - if (wakenUp.compareAndSet(false, true)) { - final Selector selector = this.selector; - if (selector != null) { - selector.wakeup(); - } - } - } - - final void selectNow() throws IOException { - final Selector selector = this.selector; - if (selector != null) { - selector.selectNow(); - } - } -} \ No newline at end of file + /** + * JVM bug threshold + */ + public static final int JVMBUG_THRESHHOLD = + Integer.getInteger("com.googlecode.yanf4j.nio.JVMBUG_THRESHHOLD", 128); + public static final int JVMBUG_THRESHHOLD2 = JVMBUG_THRESHHOLD * 2; + public static final int JVMBUG_THRESHHOLD1 = (JVMBUG_THRESHHOLD2 + JVMBUG_THRESHHOLD) / 2; + public static final int DEFAULT_WAIT = 1000; + + private static final Logger log = LoggerFactory.getLogger("remoting"); + + private boolean jvmBug0; + private boolean jvmBug1; + + private final int reactorIndex; + + private final SelectorManager selectorManager; + + private final AtomicInteger jvmBug = new AtomicInteger(0); + + private long lastJVMBug; + + private Selector selector; + + private final NioController controller; + + private final Configuration configuration; + + static public class PaddingAtomicBoolean extends AtomicBoolean { + + /** + * + */ + private static final long serialVersionUID = 5227571972657902891L; + public int p1; + public long p2, p3, p4, p5, p6, p7, p8; + + PaddingAtomicBoolean(boolean v) { + super(v); + } + } + + private final AtomicBoolean wakenUp = new PaddingAtomicBoolean(false); + + public static class RegisterEvent { + SelectableChannel channel; + int ops; + EventType eventType; + Object attachment; + Session session; + + public RegisterEvent(SelectableChannel channel, int ops, Object attachment) { + super(); + this.channel = channel; + this.ops = ops; + this.attachment = attachment; + } + + public RegisterEvent(Session session, EventType eventType) { + super(); + this.session = session; + this.eventType = eventType; + } + } + + private Queue register; + + private final Lock gate = new ReentrantLock(); + + private int selectTries = 0; + + private long nextTimeout = 0; + + private long lastCheckTimestamp = 0L; + + Reactor(SelectorManager selectorManager, Configuration configuration, int index) + throws IOException { + super(); + reactorIndex = index; + this.register = (Queue) SystemUtils.createTransferQueue(); + this.selectorManager = selectorManager; + controller = selectorManager.getController(); + selector = SystemUtils.openSelector(); + this.configuration = configuration; + setName("Xmemcached-Reactor-" + index); + setDaemon(true); + } + + public final Selector getSelector() { + return selector; + } + + public int getReactorIndex() { + return reactorIndex; + } + + @Override + public void run() { + selectorManager.notifyReady(); + while (selectorManager.isStarted() && selector.isOpen()) { + try { + beforeSelect(); + wakenUp.set(false); + long before = -1; + // Wether to look jvm bug + if (SystemUtils.isLinuxPlatform() && !SystemUtils.isAfterJava6u4Version()) { + before = System.currentTimeMillis(); + } + long wait = DEFAULT_WAIT; + if (nextTimeout > 0) { + wait = nextTimeout; + } + int selected = selector.select(wait); + if (selected == 0) { + if (before != -1) { + lookJVMBug(before, selected, wait); + } + selectTries++; + // check timeout and idle + nextTimeout = checkSessionTimeout(); + continue; + } else { + selectTries = 0; + } + + } catch (ClosedSelectorException e) { + break; + } catch (IOException e) { + log.error("Reactor select error", e); + if (selector.isOpen()) { + continue; + } else { + break; + } + } + Set selectedKeys = selector.selectedKeys(); + gate.lock(); + try { + postSelect(selectedKeys, selector.keys()); + dispatchEvent(selectedKeys); + } finally { + gate.unlock(); + } + } + if (selector != null) { + if (selector.isOpen()) { + try { + controller.closeChannel(selector); + selector.close(); + } catch (IOException e) { + controller.notifyException(e); + log.error("stop reactor error", e); + } + } + } + + } + + /** + * Look jvm bug + * + * @param before + * @param selected + * @param wait + * @return + * @throws IOException + */ + private boolean lookJVMBug(long before, int selected, long wait) throws IOException { + boolean seeing = false; + long now = System.currentTimeMillis(); + + if (JVMBUG_THRESHHOLD > 0 && selected == 0 && wait > JVMBUG_THRESHHOLD + && now - before < wait / 4 && !wakenUp.get() /* waken up */ + && !Thread.currentThread().isInterrupted()/* Interrupted */) { + jvmBug.incrementAndGet(); + if (jvmBug.get() >= JVMBUG_THRESHHOLD2) { + gate.lock(); + try { + lastJVMBug = now; + log.warn("JVM bug occured at " + new Date(lastJVMBug) + + ",http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6403933,reactIndex=" + + reactorIndex); + if (jvmBug1) { + log.debug("seeing JVM BUG(s) - recreating selector,reactIndex=" + reactorIndex); + } else { + jvmBug1 = true; + log.info("seeing JVM BUG(s) - recreating selector,reactIndex=" + reactorIndex); + } + seeing = true; + final Selector new_selector = SystemUtils.openSelector(); + + for (SelectionKey k : selector.keys()) { + if (!k.isValid() || k.interestOps() == 0) { + continue; + } + + final SelectableChannel channel = k.channel(); + final Object attachment = k.attachment(); + + channel.register(new_selector, k.interestOps(), attachment); + } + + selector.close(); + selector = new_selector; + + } finally { + gate.unlock(); + } + jvmBug.set(0); + + } else if (jvmBug.get() == JVMBUG_THRESHHOLD || jvmBug.get() == JVMBUG_THRESHHOLD1) { + if (jvmBug0) { + log.debug("seeing JVM BUG(s) - cancelling interestOps==0,reactIndex=" + reactorIndex); + } else { + jvmBug0 = true; + log.info("seeing JVM BUG(s) - cancelling interestOps==0,reactIndex=" + reactorIndex); + } + gate.lock(); + seeing = true; + try { + for (SelectionKey k : selector.keys()) { + if (k.isValid() && k.interestOps() == 0) { + k.cancel(); + } + } + } finally { + gate.unlock(); + } + } + } else { + jvmBug.set(0); + } + return seeing; + } + + /** + * Dispatch selected event + * + * @param selectedKeySet + */ + public final void dispatchEvent(Set selectedKeySet) { + Iterator it = selectedKeySet.iterator(); + boolean skipOpRead = false; + while (it.hasNext()) { + SelectionKey key = it.next(); + it.remove(); + if (!key.isValid()) { + if (key.attachment() != null) { + controller.closeSelectionKey(key); + } else { + key.cancel(); + } + continue; + } + try { + if (key.isValid() && key.isAcceptable()) { + controller.onAccept(key); + continue; + } + if (key.isValid() && (key.readyOps() & SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE) { + // Remove write interest + key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE); + controller.onWrite(key); + if (!controller.isHandleReadWriteConcurrently()) { + skipOpRead = true; + } + } + if (!skipOpRead && key.isValid() + && (key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) { + key.interestOps(key.interestOps() & ~SelectionKey.OP_READ); + if (!controller.getStatistics().isReceiveOverFlow()) { + // Remove read interest + controller.onRead(key); + } else { + key.interestOps(key.interestOps() | SelectionKey.OP_READ); + } + + } + if ((key.readyOps() & SelectionKey.OP_CONNECT) == SelectionKey.OP_CONNECT) { + controller.onConnect(key); + } + + } catch (CancelledKeyException e) { + // ignore + } catch (RejectedExecutionException e) { + + if (key.attachment() instanceof AbstractNioSession) { + ((AbstractNioSession) key.attachment()).onException(e); + } + controller.notifyException(e); + if (selector.isOpen()) { + continue; + } else { + break; + } + } catch (Exception e) { + if (key.attachment() instanceof AbstractNioSession) { + ((AbstractNioSession) key.attachment()).onException(e); + } + controller.closeSelectionKey(key); + controller.notifyException(e); + log.error("Reactor dispatch events error", e); + if (selector.isOpen()) { + continue; + } else { + break; + } + } + } + } + + final void unregisterChannel(SelectableChannel channel) throws IOException { + Selector selector = this.selector; + if (selector != null) { + if (channel != null) { + SelectionKey key = channel.keyFor(selector); + if (key != null) { + key.cancel(); + } + } + } + wakeup(); + } + + /** + * Check session timeout or idle + * + * @return + */ + private final long checkSessionTimeout() { + long nextTimeout = 0; + if (configuration.getCheckSessionTimeoutInterval() > 0) { + gate.lock(); + try { + if (isNeedCheckSessionIdleTimeout()) { + nextTimeout = configuration.getCheckSessionTimeoutInterval(); + for (SelectionKey key : selector.keys()) { + + if (key.attachment() != null) { + long n = checkExpiredIdle(key, getSessionFromAttchment(key)); + nextTimeout = n < nextTimeout ? n : nextTimeout; + } + } + selectTries = 0; + lastCheckTimestamp = System.currentTimeMillis(); + } + } finally { + gate.unlock(); + } + } + return nextTimeout; + } + + private boolean isNeedCheckSessionIdleTimeout() { + return selectTries * 1000 >= configuration.getCheckSessionTimeoutInterval() + || System.currentTimeMillis() - this.lastCheckTimestamp >= configuration + .getCheckSessionTimeoutInterval(); + } + + private final Session getSessionFromAttchment(SelectionKey key) { + if (key.attachment() instanceof Session) { + return (Session) key.attachment(); + } + return null; + } + + public final void registerSession(Session session, EventType event) { + final Selector selector = this.selector; + if (isReactorThread() && selector != null) { + dispatchSessionEvent(session, event); + } else { + register.offer(new RegisterEvent(session, event)); + wakeup(); + } + } + + private final boolean isReactorThread() { + return Thread.currentThread() == this; + } + + final void beforeSelect() { + controller.checkStatisticsForRestart(); + processRegister(); + } + + private final void processRegister() { + RegisterEvent event = null; + while ((event = register.poll()) != null) { + if (event.session != null) { + dispatchSessionEvent(event.session, event.eventType); + } else { + registerChannelNow(event.channel, event.ops, event.attachment); + } + } + } + + Configuration getConfiguration() { + return configuration; + } + + private final void dispatchSessionEvent(Session session, EventType event) { + if (session.isClosed() && event != EventType.UNREGISTER) { + return; + } + switch (event) { + case REGISTER: + controller.registerSession(session); + break; + case UNREGISTER: + controller.unregisterSession(session); + break; + default: + ((NioSession) session).onEvent(event, selector); + break; + } + } + + public final void postSelect(Set selectedKeys, Set allKeys) { + if (controller.getSessionTimeout() > 0 || controller.getSessionIdleTimeout() > 0) { + if (isNeedCheckSessionIdleTimeout()) { + for (SelectionKey key : allKeys) { + if (!selectedKeys.contains(key)) { + if (key.attachment() != null) { + checkExpiredIdle(key, getSessionFromAttchment(key)); + } + } + } + lastCheckTimestamp = System.currentTimeMillis(); + } + } + } + + private long checkExpiredIdle(SelectionKey key, Session session) { + if (session == null) { + return 0; + } + long nextTimeout = 0; + boolean expired = false; + if (controller.getSessionTimeout() > 0) { + expired = checkExpired(key, session); + nextTimeout = controller.getSessionTimeout(); + } + if (controller.getSessionIdleTimeout() > 0 && !expired) { + checkIdle(session); + nextTimeout = controller.getSessionIdleTimeout(); + } + return nextTimeout; + } + + private final void checkIdle(Session session) { + if (controller.getSessionIdleTimeout() > 0) { + if (session.isIdle()) { + ((NioSession) session).onEvent(EventType.IDLE, selector); + } + } + } + + private final boolean checkExpired(SelectionKey key, Session session) { + if (session != null && session.isExpired()) { + ((NioSession) session).onEvent(EventType.EXPIRED, selector); + controller.closeSelectionKey(key); + return true; + } + return false; + } + + public final void registerChannel(SelectableChannel channel, int ops, Object attachment) { + if (isReactorThread()) { + registerChannelNow(channel, ops, attachment); + } else { + register.offer(new RegisterEvent(channel, ops, attachment)); + wakeup(); + } + + } + + private void registerChannelNow(SelectableChannel channel, int ops, Object attachment) { + if (channel.isOpen()) { + gate.lock(); + try { + channel.register(selector, ops, attachment); + + } catch (ClosedChannelException e) { + log.error("Register channel error", e); + controller.notifyException(e); + } finally { + gate.unlock(); + } + } + } + + final void wakeup() { + if (wakenUp.compareAndSet(false, true)) { + final Selector selector = this.selector; + if (selector != null) { + selector.wakeup(); + } + } + } + + final void selectNow() throws IOException { + final Selector selector = this.selector; + if (selector != null) { + selector.selectNow(); + } + } +} diff --git a/src/main/java/com/google/code/yanf4j/nio/impl/SelectorManager.java b/src/main/java/com/google/code/yanf4j/nio/impl/SelectorManager.java index 9dffddc03..09f2e998f 100644 --- a/src/main/java/com/google/code/yanf4j/nio/impl/SelectorManager.java +++ b/src/main/java/com/google/code/yanf4j/nio/impl/SelectorManager.java @@ -4,10 +4,8 @@ import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; import java.util.concurrent.atomic.AtomicInteger; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import com.google.code.yanf4j.config.Configuration; import com.google.code.yanf4j.core.EventType; import com.google.code.yanf4j.core.Session; @@ -19,178 +17,173 @@ * */ public class SelectorManager { - private final Reactor[] reactorSet; - private final AtomicInteger sets = new AtomicInteger(0); - private final NioController controller; - private final int dividend; - - /** - * Reactor count which are ready - */ - private int reactorReadyCount; - - public SelectorManager(int selectorPoolSize, NioController controller, - Configuration conf) throws IOException { - if (selectorPoolSize <= 0) { - throw new IllegalArgumentException("selectorPoolSize<=0"); - } - log.info("Creating " + selectorPoolSize + " reactors..."); - reactorSet = new Reactor[selectorPoolSize]; - this.controller = controller; - for (int i = 0; i < selectorPoolSize; i++) { - reactorSet[i] = new Reactor(this, conf, i); - } - dividend = reactorSet.length - 1; - } - - private volatile boolean started; - - public int getSelectorCount() { - return reactorSet == null ? 0 : reactorSet.length; - } - - public synchronized void start() { - if (started) { - return; - } - started = true; - for (Reactor reactor : reactorSet) { - reactor.start(); - } - } - - Reactor getReactorFromSession(Session session) { - Reactor reactor = (Reactor) session.getAttribute(REACTOR_ATTRIBUTE); - - if (reactor == null) { - reactor = nextReactor(); - final Reactor oldReactor = (Reactor) session - .setAttributeIfAbsent(REACTOR_ATTRIBUTE, reactor); - if (oldReactor != null) { - reactor = oldReactor; - } - } - return reactor; - } - - /** - * Find reactor by index - * - * @param index - * @return - */ - public Reactor getReactorByIndex(int index) { - if (index < 0 || index > reactorSet.length - 1) { - throw new ArrayIndexOutOfBoundsException(); - } - return reactorSet[index]; - } - - public synchronized void stop() { - if (!started) { - return; - } - started = false; - for (Reactor reactor : reactorSet) { - reactor.interrupt(); - } - } - - public static final String REACTOR_ATTRIBUTE = System.currentTimeMillis() - + "_Reactor_Attribute"; - - /** - * Register channel - * - * @param channel - * @param ops - * @param attachment - * @return - */ - public final Reactor registerChannel(SelectableChannel channel, int ops, - Object attachment) { - awaitReady(); - int index = 0; - // Accept event used index 0 reactor - if (ops == SelectionKey.OP_ACCEPT || ops == SelectionKey.OP_CONNECT) { - index = 0; - } else { - index = sets.incrementAndGet() % dividend + 1; - } - final Reactor reactor = reactorSet[index]; - reactor.registerChannel(channel, ops, attachment); - return reactor; - - } - - void awaitReady() { - synchronized (this) { - while (!started || reactorReadyCount != reactorSet.length) { - try { - this.wait(1000); - } catch (InterruptedException e) { - Thread.currentThread().interrupt();// reset interrupt status - } - } - } - } - - /** - * Get next reactor - * - * @return - */ - public final Reactor nextReactor() { - if (dividend > 0) { - return reactorSet[sets.incrementAndGet() % dividend + 1]; - } else { - return reactorSet[0]; - } - } - - /** - * Register session - * - * @param session - * @param event - */ - public final void registerSession(Session session, EventType event) { - if (session.isClosed() && event != EventType.UNREGISTER) { - return; - } - Reactor reactor = (Reactor) session.getAttribute(REACTOR_ATTRIBUTE); - - if (reactor == null) { - reactor = nextReactor(); - final Reactor oldReactor = (Reactor) session - .setAttributeIfAbsent(REACTOR_ATTRIBUTE, reactor); - if (oldReactor != null) { - reactor = oldReactor; - } - } - reactor.registerSession(session, event); - } - - public NioController getController() { - return controller; - } - - /** - * Notify all reactor have been ready - */ - synchronized void notifyReady() { - reactorReadyCount++; - if (reactorReadyCount == reactorSet.length) { - controller.notifyReady(); - notifyAll(); - } - - } - - private static final Logger log = LoggerFactory - .getLogger(SelectorManager.class); - - public final boolean isStarted() { - return started; - } + private final Reactor[] reactorSet; + private final AtomicInteger sets = new AtomicInteger(0); + private final NioController controller; + private final int dividend; + + /** + * Reactor count which are ready + */ + private int reactorReadyCount; + + public SelectorManager(int selectorPoolSize, NioController controller, Configuration conf) + throws IOException { + if (selectorPoolSize <= 0) { + throw new IllegalArgumentException("selectorPoolSize<=0"); + } + log.info("Creating " + selectorPoolSize + " reactors..."); + reactorSet = new Reactor[selectorPoolSize]; + this.controller = controller; + for (int i = 0; i < selectorPoolSize; i++) { + reactorSet[i] = new Reactor(this, conf, i); + } + dividend = reactorSet.length - 1; + } + + private volatile boolean started; + + public int getSelectorCount() { + return reactorSet == null ? 0 : reactorSet.length; + } + + public synchronized void start() { + if (started) { + return; + } + started = true; + for (Reactor reactor : reactorSet) { + reactor.start(); + } + } + + Reactor getReactorFromSession(Session session) { + Reactor reactor = (Reactor) session.getAttribute(REACTOR_ATTRIBUTE); + + if (reactor == null) { + reactor = nextReactor(); + final Reactor oldReactor = (Reactor) session.setAttributeIfAbsent(REACTOR_ATTRIBUTE, reactor); + if (oldReactor != null) { + reactor = oldReactor; + } + } + return reactor; + } + + /** + * Find reactor by index + * + * @param index + * @return + */ + public Reactor getReactorByIndex(int index) { + if (index < 0 || index > reactorSet.length - 1) { + throw new ArrayIndexOutOfBoundsException(); + } + return reactorSet[index]; + } + + public synchronized void stop() { + if (!started) { + return; + } + started = false; + for (Reactor reactor : reactorSet) { + reactor.interrupt(); + } + } + + public static final String REACTOR_ATTRIBUTE = System.currentTimeMillis() + "_Reactor_Attribute"; + + /** + * Register channel + * + * @param channel + * @param ops + * @param attachment + * @return + */ + public final Reactor registerChannel(SelectableChannel channel, int ops, Object attachment) { + awaitReady(); + int index = 0; + // Accept event used index 0 reactor + if (ops == SelectionKey.OP_ACCEPT || ops == SelectionKey.OP_CONNECT) { + index = 0; + } else { + index = sets.incrementAndGet() % dividend + 1; + } + final Reactor reactor = reactorSet[index]; + reactor.registerChannel(channel, ops, attachment); + return reactor; + + } + + void awaitReady() { + synchronized (this) { + while (!started || reactorReadyCount != reactorSet.length) { + try { + this.wait(1000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt();// reset interrupt status + } + } + } + } + + /** + * Get next reactor + * + * @return + */ + public final Reactor nextReactor() { + if (dividend > 0) { + return reactorSet[sets.incrementAndGet() % dividend + 1]; + } else { + return reactorSet[0]; + } + } + + /** + * Register session + * + * @param session + * @param event + */ + public final void registerSession(Session session, EventType event) { + if (session.isClosed() && event != EventType.UNREGISTER) { + return; + } + Reactor reactor = (Reactor) session.getAttribute(REACTOR_ATTRIBUTE); + + if (reactor == null) { + reactor = nextReactor(); + final Reactor oldReactor = (Reactor) session.setAttributeIfAbsent(REACTOR_ATTRIBUTE, reactor); + if (oldReactor != null) { + reactor = oldReactor; + } + } + reactor.registerSession(session, event); + } + + public NioController getController() { + return controller; + } + + /** + * Notify all reactor have been ready + */ + synchronized void notifyReady() { + reactorReadyCount++; + if (reactorReadyCount == reactorSet.length) { + controller.notifyReady(); + notifyAll(); + } + + } + + private static final Logger log = LoggerFactory.getLogger(SelectorManager.class); + + public final boolean isStarted() { + return started; + } } diff --git a/src/main/java/com/google/code/yanf4j/nio/impl/SocketChannelController.java b/src/main/java/com/google/code/yanf4j/nio/impl/SocketChannelController.java index 16f0cf12d..b7f8bdc71 100644 --- a/src/main/java/com/google/code/yanf4j/nio/impl/SocketChannelController.java +++ b/src/main/java/com/google/code/yanf4j/nio/impl/SocketChannelController.java @@ -4,7 +4,6 @@ import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; import java.util.Queue; - import com.google.code.yanf4j.config.Configuration; import com.google.code.yanf4j.core.CodecFactory; import com.google.code.yanf4j.core.EventType; @@ -23,110 +22,94 @@ */ public abstract class SocketChannelController extends NioController { - protected boolean soLingerOn = false; - - public void setSoLinger(boolean on, int value) { - this.soLingerOn = on; - this.socketOptions.put(StandardSocketOption.SO_LINGER, value); - } - - public SocketChannelController() { - super(); - } - - public SocketChannelController(Configuration configuration) { - super(configuration, null, null); - - } - - public SocketChannelController(Configuration configuration, - CodecFactory codecFactory) { - super(configuration, null, codecFactory); - } - - public SocketChannelController(Configuration configuration, Handler handler, - CodecFactory codecFactory) { - super(configuration, handler, codecFactory); - } - - @Override - protected final void dispatchReadEvent(SelectionKey key) { - Session session = (Session) key.attachment(); - if (session != null) { - ((NioSession) session).onEvent(EventType.READABLE, key.selector()); - } else { - log.warn( - "Could not find session for readable event,maybe it is closed"); - } - } - - @Override - protected final void dispatchWriteEvent(SelectionKey key) { - Session session = (Session) key.attachment(); - if (session != null) { - ((NioSession) session).onEvent(EventType.WRITEABLE, key.selector()); - } else { - log.warn( - "Could not find session for writable event,maybe it is closed"); - } - - } - - protected NioSession buildSession(SocketChannel sc) { - Queue queue = buildQueue(); - NioSessionConfig sessionConfig = buildSessionConfig(sc, queue); - NioSession session = new NioTCPSession(sessionConfig, - this.configuration.getSessionReadBufferSize()); - return session; - } - - /** - * Confiure socket channel - * - * @param sc - * @throws IOException - */ - protected final void configureSocketChannel(SocketChannel sc) - throws IOException { - sc.socket().setSoTimeout(this.soTimeout); - sc.configureBlocking(false); - if (this.socketOptions.get(StandardSocketOption.SO_REUSEADDR) != null) { - sc.socket() - .setReuseAddress(StandardSocketOption.SO_REUSEADDR.type() - .cast(this.socketOptions - .get(StandardSocketOption.SO_REUSEADDR))); - } - if (this.socketOptions.get(StandardSocketOption.SO_SNDBUF) != null) { - sc.socket() - .setSendBufferSize(StandardSocketOption.SO_SNDBUF.type() - .cast(this.socketOptions - .get(StandardSocketOption.SO_SNDBUF))); - } - if (this.socketOptions.get(StandardSocketOption.SO_KEEPALIVE) != null) { - sc.socket() - .setKeepAlive(StandardSocketOption.SO_KEEPALIVE.type() - .cast(this.socketOptions - .get(StandardSocketOption.SO_KEEPALIVE))); - } - if (this.socketOptions.get(StandardSocketOption.SO_LINGER) != null) { - sc.socket().setSoLinger(this.soLingerOn, - StandardSocketOption.SO_LINGER.type() - .cast(this.socketOptions - .get(StandardSocketOption.SO_LINGER))); - } - if (this.socketOptions.get(StandardSocketOption.SO_RCVBUF) != null) { - sc.socket() - .setReceiveBufferSize(StandardSocketOption.SO_RCVBUF.type() - .cast(this.socketOptions - .get(StandardSocketOption.SO_RCVBUF))); - - } - if (this.socketOptions.get(StandardSocketOption.TCP_NODELAY) != null) { - sc.socket() - .setTcpNoDelay(StandardSocketOption.TCP_NODELAY.type() - .cast(this.socketOptions - .get(StandardSocketOption.TCP_NODELAY))); - } - } + protected boolean soLingerOn = false; + + public void setSoLinger(boolean on, int value) { + this.soLingerOn = on; + this.socketOptions.put(StandardSocketOption.SO_LINGER, value); + } + + public SocketChannelController() { + super(); + } + + public SocketChannelController(Configuration configuration) { + super(configuration, null, null); + + } + + public SocketChannelController(Configuration configuration, CodecFactory codecFactory) { + super(configuration, null, codecFactory); + } + + public SocketChannelController(Configuration configuration, Handler handler, + CodecFactory codecFactory) { + super(configuration, handler, codecFactory); + } + + @Override + protected final void dispatchReadEvent(SelectionKey key) { + Session session = (Session) key.attachment(); + if (session != null) { + ((NioSession) session).onEvent(EventType.READABLE, key.selector()); + } else { + log.warn("Could not find session for readable event,maybe it is closed"); + } + } + + @Override + protected final void dispatchWriteEvent(SelectionKey key) { + Session session = (Session) key.attachment(); + if (session != null) { + ((NioSession) session).onEvent(EventType.WRITEABLE, key.selector()); + } else { + log.warn("Could not find session for writable event,maybe it is closed"); + } + + } + + protected NioSession buildSession(SocketChannel sc) { + Queue queue = buildQueue(); + NioSessionConfig sessionConfig = buildSessionConfig(sc, queue); + NioSession session = + new NioTCPSession(sessionConfig, this.configuration.getSessionReadBufferSize()); + return session; + } + + /** + * Confiure socket channel + * + * @param sc + * @throws IOException + */ + protected final void configureSocketChannel(SocketChannel sc) throws IOException { + sc.socket().setSoTimeout(this.soTimeout); + sc.configureBlocking(false); + if (this.socketOptions.get(StandardSocketOption.SO_REUSEADDR) != null) { + sc.socket().setReuseAddress(StandardSocketOption.SO_REUSEADDR.type() + .cast(this.socketOptions.get(StandardSocketOption.SO_REUSEADDR))); + } + if (this.socketOptions.get(StandardSocketOption.SO_SNDBUF) != null) { + sc.socket().setSendBufferSize(StandardSocketOption.SO_SNDBUF.type() + .cast(this.socketOptions.get(StandardSocketOption.SO_SNDBUF))); + } + if (this.socketOptions.get(StandardSocketOption.SO_KEEPALIVE) != null) { + sc.socket().setKeepAlive(StandardSocketOption.SO_KEEPALIVE.type() + .cast(this.socketOptions.get(StandardSocketOption.SO_KEEPALIVE))); + } + if (this.socketOptions.get(StandardSocketOption.SO_LINGER) != null) { + sc.socket().setSoLinger(this.soLingerOn, StandardSocketOption.SO_LINGER.type() + .cast(this.socketOptions.get(StandardSocketOption.SO_LINGER))); + } + if (this.socketOptions.get(StandardSocketOption.SO_RCVBUF) != null) { + sc.socket().setReceiveBufferSize(StandardSocketOption.SO_RCVBUF.type() + .cast(this.socketOptions.get(StandardSocketOption.SO_RCVBUF))); + + } + if (this.socketOptions.get(StandardSocketOption.TCP_NODELAY) != null) { + sc.socket().setTcpNoDelay(StandardSocketOption.TCP_NODELAY.type() + .cast(this.socketOptions.get(StandardSocketOption.TCP_NODELAY))); + } + } } diff --git a/src/main/java/com/google/code/yanf4j/nio/package.html b/src/main/java/com/google/code/yanf4j/nio/package.html index 17438d62a..efbf37921 100644 --- a/src/main/java/com/google/code/yanf4j/nio/package.html +++ b/src/main/java/com/google/code/yanf4j/nio/package.html @@ -1,14 +1,10 @@ - - + - -Nio implementation - - - -

Nio implementation

- - - + + Nio implementation + + +

Nio implementation

+ + \ No newline at end of file diff --git a/src/main/java/com/google/code/yanf4j/statistics/Statistics.java b/src/main/java/com/google/code/yanf4j/statistics/Statistics.java index 1c88c9ae3..4e1dbc312 100644 --- a/src/main/java/com/google/code/yanf4j/statistics/Statistics.java +++ b/src/main/java/com/google/code/yanf4j/statistics/Statistics.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.statistics; @@ -30,72 +24,72 @@ */ public interface Statistics { - public void start(); + public void start(); - public void stop(); + public void stop(); - public double getReceiveBytesPerSecond(); + public double getReceiveBytesPerSecond(); - public double getSendBytesPerSecond(); + public double getSendBytesPerSecond(); - public abstract void statisticsProcess(long n); + public abstract void statisticsProcess(long n); - public abstract long getProcessedMessageCount(); + public abstract long getProcessedMessageCount(); - public abstract double getProcessedMessageAverageTime(); + public abstract double getProcessedMessageAverageTime(); - public abstract void statisticsRead(long n); + public abstract void statisticsRead(long n); - public abstract void statisticsWrite(long n); + public abstract void statisticsWrite(long n); - public abstract long getRecvMessageCount(); + public abstract long getRecvMessageCount(); - public abstract long getRecvMessageTotalSize(); + public abstract long getRecvMessageTotalSize(); - public abstract long getRecvMessageAverageSize(); + public abstract long getRecvMessageAverageSize(); - public abstract long getWriteMessageTotalSize(); + public abstract long getWriteMessageTotalSize(); - public abstract long getWriteMessageCount(); + public abstract long getWriteMessageCount(); - public abstract long getWriteMessageAverageSize(); + public abstract long getWriteMessageAverageSize(); - public abstract double getRecvMessageCountPerSecond(); + public abstract double getRecvMessageCountPerSecond(); - public abstract double getWriteMessageCountPerSecond(); + public abstract double getWriteMessageCountPerSecond(); - public void statisticsAccept(); + public void statisticsAccept(); - public double getAcceptCountPerSecond(); + public double getAcceptCountPerSecond(); - public long getStartedTime(); + public long getStartedTime(); - public void reset(); + public void reset(); - public void restart(); + public void restart(); - public boolean isStatistics(); + public boolean isStatistics(); - public void setReceiveThroughputLimit(double receiveThroughputLimit); + public void setReceiveThroughputLimit(double receiveThroughputLimit); - /** - * Check session if receive bytes per second is over flow controll - * - * @return - */ - public boolean isReceiveOverFlow(); + /** + * Check session if receive bytes per second is over flow controll + * + * @return + */ + public boolean isReceiveOverFlow(); - /** - * Check session if receive bytes per second is over flow controll - * - * @return - */ - public boolean isSendOverFlow(); + /** + * Check session if receive bytes per second is over flow controll + * + * @return + */ + public boolean isSendOverFlow(); - public double getSendThroughputLimit(); + public double getSendThroughputLimit(); - public void setSendThroughputLimit(double sendThroughputLimit); + public void setSendThroughputLimit(double sendThroughputLimit); - public double getReceiveThroughputLimit(); + public double getReceiveThroughputLimit(); -} \ No newline at end of file +} diff --git a/src/main/java/com/google/code/yanf4j/statistics/impl/DefaultStatistics.java b/src/main/java/com/google/code/yanf4j/statistics/impl/DefaultStatistics.java index f81245afc..faab0dcb4 100644 --- a/src/main/java/com/google/code/yanf4j/statistics/impl/DefaultStatistics.java +++ b/src/main/java/com/google/code/yanf4j/statistics/impl/DefaultStatistics.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.statistics.impl; @@ -31,126 +25,124 @@ * */ public class DefaultStatistics implements Statistics { - public void start() { + public void start() { - } + } - public double getSendBytesPerSecond() { - return 0; - } + public double getSendBytesPerSecond() { + return 0; + } - public double getReceiveBytesPerSecond() { - return 0; - } + public double getReceiveBytesPerSecond() { + return 0; + } - public boolean isStatistics() { - return false; - } + public boolean isStatistics() { + return false; + } - public long getStartedTime() { - return 0; - } + public long getStartedTime() { + return 0; + } - public void reset() { + public void reset() { - } + } - public void restart() { + public void restart() { - } + } - public double getProcessedMessageAverageTime() { - return 0; - } + public double getProcessedMessageAverageTime() { + return 0; + } - public long getProcessedMessageCount() { - return 0; - } + public long getProcessedMessageCount() { + return 0; + } - public void statisticsProcess(long n) { + public void statisticsProcess(long n) { - } + } - public void stop() { + public void stop() { - } + } - public long getRecvMessageCount() { + public long getRecvMessageCount() { - return 0; - } + return 0; + } - public long getRecvMessageTotalSize() { + public long getRecvMessageTotalSize() { - return 0; - } + return 0; + } - public long getRecvMessageAverageSize() { + public long getRecvMessageAverageSize() { - return 0; - } + return 0; + } - public double getRecvMessageCountPerSecond() { + public double getRecvMessageCountPerSecond() { - return 0; - } + return 0; + } - public long getWriteMessageCount() { + public long getWriteMessageCount() { - return 0; - } + return 0; + } - public long getWriteMessageTotalSize() { + public long getWriteMessageTotalSize() { - return 0; - } + return 0; + } - public long getWriteMessageAverageSize() { + public long getWriteMessageAverageSize() { - return 0; - } + return 0; + } - public void statisticsRead(long n) { + public void statisticsRead(long n) { - } + } - public void statisticsWrite(long n) { + public void statisticsWrite(long n) { - } + } - public double getWriteMessageCountPerSecond() { + public double getWriteMessageCountPerSecond() { - return 0; - } + return 0; + } - public double getAcceptCountPerSecond() { - return 0; - } + public double getAcceptCountPerSecond() { + return 0; + } - public void statisticsAccept() { + public void statisticsAccept() { - } + } - public void setReceiveThroughputLimit(double receivePacketRate) { - } + public void setReceiveThroughputLimit(double receivePacketRate) {} - public boolean isReceiveOverFlow() { - return false; - } + public boolean isReceiveOverFlow() { + return false; + } - public boolean isSendOverFlow() { - return false; - } + public boolean isSendOverFlow() { + return false; + } - public double getSendThroughputLimit() { - return -1.0; - } + public double getSendThroughputLimit() { + return -1.0; + } - public void setSendThroughputLimit(double sendThroughputLimit) { - } + public void setSendThroughputLimit(double sendThroughputLimit) {} - public final double getReceiveThroughputLimit() { - return -1.0; - } + public final double getReceiveThroughputLimit() { + return -1.0; + } } diff --git a/src/main/java/com/google/code/yanf4j/statistics/impl/SimpleStatistics.java b/src/main/java/com/google/code/yanf4j/statistics/impl/SimpleStatistics.java index 1f32ad67d..483bd3792 100644 --- a/src/main/java/com/google/code/yanf4j/statistics/impl/SimpleStatistics.java +++ b/src/main/java/com/google/code/yanf4j/statistics/impl/SimpleStatistics.java @@ -1,29 +1,22 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.statistics.impl; import java.util.concurrent.atomic.AtomicLong; - import com.google.code.yanf4j.statistics.Statistics; /** @@ -33,232 +26,212 @@ * */ public class SimpleStatistics implements Statistics { - private boolean started = false; - - public boolean isStatistics() { - return this.started; - } - - public synchronized void reset() { - if (this.started) { - throw new IllegalStateException(); - } - this.startTime = this.stopTime = -1; - this.recvMessageCount.set(0); - this.recvMessageTotalSize.set(0); - this.writeMessageCount.set(0); - this.writeMessageTotalSize.set(0); - this.processMessageCount.set(0); - this.processMessageTotalTime.set(0); - this.acceptCount.set(0); - } - - private double receiveThroughputLimit = -1.0; // receive bytes per second - private double sendThroughputLimit = -1.0; // send bytes per second - - public void setReceiveThroughputLimit(double receivePacketRate) { - this.receiveThroughputLimit = receivePacketRate; - } - - /** - * Check session if receive bytes per second is over flow controll - * - * @return - */ - public boolean isReceiveOverFlow() { - if (getReceiveThroughputLimit() < 0.0000f) { - return false; - } - return getReceiveBytesPerSecond() > getReceiveThroughputLimit(); - } - - /** - * Check session if receive bytes per second is over flow controll - * - * @return - */ - public boolean isSendOverFlow() { - if (getSendThroughputLimit() < 0.0000f) { - return false; - } - return getSendBytesPerSecond() > getSendThroughputLimit(); - } - - public double getSendThroughputLimit() { - return this.sendThroughputLimit; - } - - public void setSendThroughputLimit(double sendThroughputLimit) { - this.sendThroughputLimit = sendThroughputLimit; - } - - public final double getReceiveThroughputLimit() { - return this.receiveThroughputLimit; - } - - public synchronized void restart() { - stop(); - reset(); - start(); - } - - private long startTime, stopTime = -1; - - private AtomicLong recvMessageCount = new AtomicLong(); - - private AtomicLong recvMessageTotalSize = new AtomicLong(); - - private AtomicLong writeMessageCount = new AtomicLong(); - - private AtomicLong writeMessageTotalSize = new AtomicLong(); - - private AtomicLong processMessageCount = new AtomicLong(); - - private AtomicLong acceptCount = new AtomicLong(); - - private AtomicLong processMessageTotalTime = new AtomicLong(); - - public long getStartedTime() { - return this.startTime; - } - - public double getProcessedMessageAverageTime() { - return this.processMessageCount.get() == 0 - ? 0 - : (double) this.processMessageTotalTime.get() - / this.processMessageCount.get(); - } - - public long getProcessedMessageCount() { - return this.processMessageCount.get(); - } - - public void statisticsProcess(long n) { - if (!this.started) { - return; - } - if (n < 0) { - return; - } - this.processMessageTotalTime.addAndGet(n); - this.processMessageCount.incrementAndGet(); - } - - public SimpleStatistics() { - - } - - public synchronized void start() { - this.startTime = System.currentTimeMillis(); - this.started = true; - } - - public synchronized void stop() { - this.stopTime = System.currentTimeMillis(); - this.started = false; - } - - public void statisticsRead(long n) { - if (!this.started) { - return; - } - if (n <= 0) { - return; - } - this.recvMessageCount.incrementAndGet(); - this.recvMessageTotalSize.addAndGet(n); - } - - public long getRecvMessageCount() { - return this.recvMessageCount.get(); - } - - public long getRecvMessageTotalSize() { - return this.recvMessageTotalSize.get(); - } - - public long getWriteMessageCount() { - return this.writeMessageCount.get(); - } - - public long getWriteMessageTotalSize() { - return this.writeMessageTotalSize.get(); - } - - public void statisticsWrite(long n) { - if (!this.started) { - return; - } - if (n <= 0) { - return; - } - this.writeMessageCount.incrementAndGet(); - this.writeMessageTotalSize.addAndGet(n); - } - - public long getRecvMessageAverageSize() { - return this.recvMessageCount.get() == 0 - ? 0 - : this.recvMessageTotalSize.get() / this.recvMessageCount.get(); - } - - public double getRecvMessageCountPerSecond() { - long duration = (this.stopTime == -1) - ? (System.currentTimeMillis() - this.startTime) - : (this.stopTime - this.startTime); - return duration == 0 - ? 0 - : (double) this.recvMessageCount.get() * 1000 / duration; - } - - public double getWriteMessageCountPerSecond() { - long duration = (this.stopTime == -1) - ? (System.currentTimeMillis() - this.startTime) - : (this.stopTime - this.startTime); - return duration == 0 - ? 0 - : (double) this.writeMessageCount.get() * 1000 / duration; - } - - public long getWriteMessageAverageSize() { - return this.writeMessageCount.get() == 0 - ? 0 - : this.writeMessageTotalSize.get() - / this.writeMessageCount.get(); - } - - public double getAcceptCountPerSecond() { - long duration = (this.stopTime == -1) - ? (System.currentTimeMillis() - this.startTime) - : (this.stopTime - this.startTime); - return duration == 0 - ? 0 - : (double) this.acceptCount.get() * 1000 / duration; - } - - public double getReceiveBytesPerSecond() { - long duration = (this.stopTime == -1) - ? (System.currentTimeMillis() - this.startTime) - : (this.stopTime - this.startTime); - return duration == 0 - ? 0 - : (double) this.recvMessageTotalSize.get() * 1000 / duration; - } - - public double getSendBytesPerSecond() { - long duration = (this.stopTime == -1) - ? (System.currentTimeMillis() - this.startTime) - : (this.stopTime - this.startTime); - return duration == 0 - ? 0 - : (double) this.writeMessageTotalSize.get() * 1000 / duration; - } - - public void statisticsAccept() { - if (!this.started) { - return; - } - this.acceptCount.incrementAndGet(); - } + private boolean started = false; + + public boolean isStatistics() { + return this.started; + } + + public synchronized void reset() { + if (this.started) { + throw new IllegalStateException(); + } + this.startTime = this.stopTime = -1; + this.recvMessageCount.set(0); + this.recvMessageTotalSize.set(0); + this.writeMessageCount.set(0); + this.writeMessageTotalSize.set(0); + this.processMessageCount.set(0); + this.processMessageTotalTime.set(0); + this.acceptCount.set(0); + } + + private double receiveThroughputLimit = -1.0; // receive bytes per second + private double sendThroughputLimit = -1.0; // send bytes per second + + public void setReceiveThroughputLimit(double receivePacketRate) { + this.receiveThroughputLimit = receivePacketRate; + } + + /** + * Check session if receive bytes per second is over flow controll + * + * @return + */ + public boolean isReceiveOverFlow() { + if (getReceiveThroughputLimit() < 0.0000f) { + return false; + } + return getReceiveBytesPerSecond() > getReceiveThroughputLimit(); + } + + /** + * Check session if receive bytes per second is over flow controll + * + * @return + */ + public boolean isSendOverFlow() { + if (getSendThroughputLimit() < 0.0000f) { + return false; + } + return getSendBytesPerSecond() > getSendThroughputLimit(); + } + + public double getSendThroughputLimit() { + return this.sendThroughputLimit; + } + + public void setSendThroughputLimit(double sendThroughputLimit) { + this.sendThroughputLimit = sendThroughputLimit; + } + + public final double getReceiveThroughputLimit() { + return this.receiveThroughputLimit; + } + + public synchronized void restart() { + stop(); + reset(); + start(); + } + + private long startTime, stopTime = -1; + + private AtomicLong recvMessageCount = new AtomicLong(); + + private AtomicLong recvMessageTotalSize = new AtomicLong(); + + private AtomicLong writeMessageCount = new AtomicLong(); + + private AtomicLong writeMessageTotalSize = new AtomicLong(); + + private AtomicLong processMessageCount = new AtomicLong(); + + private AtomicLong acceptCount = new AtomicLong(); + + private AtomicLong processMessageTotalTime = new AtomicLong(); + + public long getStartedTime() { + return this.startTime; + } + + public double getProcessedMessageAverageTime() { + return this.processMessageCount.get() == 0 ? 0 + : (double) this.processMessageTotalTime.get() / this.processMessageCount.get(); + } + + public long getProcessedMessageCount() { + return this.processMessageCount.get(); + } + + public void statisticsProcess(long n) { + if (!this.started) { + return; + } + if (n < 0) { + return; + } + this.processMessageTotalTime.addAndGet(n); + this.processMessageCount.incrementAndGet(); + } + + public SimpleStatistics() { + + } + + public synchronized void start() { + this.startTime = System.currentTimeMillis(); + this.started = true; + } + + public synchronized void stop() { + this.stopTime = System.currentTimeMillis(); + this.started = false; + } + + public void statisticsRead(long n) { + if (!this.started) { + return; + } + if (n <= 0) { + return; + } + this.recvMessageCount.incrementAndGet(); + this.recvMessageTotalSize.addAndGet(n); + } + + public long getRecvMessageCount() { + return this.recvMessageCount.get(); + } + + public long getRecvMessageTotalSize() { + return this.recvMessageTotalSize.get(); + } + + public long getWriteMessageCount() { + return this.writeMessageCount.get(); + } + + public long getWriteMessageTotalSize() { + return this.writeMessageTotalSize.get(); + } + + public void statisticsWrite(long n) { + if (!this.started) { + return; + } + if (n <= 0) { + return; + } + this.writeMessageCount.incrementAndGet(); + this.writeMessageTotalSize.addAndGet(n); + } + + public long getRecvMessageAverageSize() { + return this.recvMessageCount.get() == 0 ? 0 + : this.recvMessageTotalSize.get() / this.recvMessageCount.get(); + } + + public double getRecvMessageCountPerSecond() { + long duration = (this.stopTime == -1) ? (System.currentTimeMillis() - this.startTime) + : (this.stopTime - this.startTime); + return duration == 0 ? 0 : (double) this.recvMessageCount.get() * 1000 / duration; + } + + public double getWriteMessageCountPerSecond() { + long duration = (this.stopTime == -1) ? (System.currentTimeMillis() - this.startTime) + : (this.stopTime - this.startTime); + return duration == 0 ? 0 : (double) this.writeMessageCount.get() * 1000 / duration; + } + + public long getWriteMessageAverageSize() { + return this.writeMessageCount.get() == 0 ? 0 + : this.writeMessageTotalSize.get() / this.writeMessageCount.get(); + } + + public double getAcceptCountPerSecond() { + long duration = (this.stopTime == -1) ? (System.currentTimeMillis() - this.startTime) + : (this.stopTime - this.startTime); + return duration == 0 ? 0 : (double) this.acceptCount.get() * 1000 / duration; + } + + public double getReceiveBytesPerSecond() { + long duration = (this.stopTime == -1) ? (System.currentTimeMillis() - this.startTime) + : (this.stopTime - this.startTime); + return duration == 0 ? 0 : (double) this.recvMessageTotalSize.get() * 1000 / duration; + } + + public double getSendBytesPerSecond() { + long duration = (this.stopTime == -1) ? (System.currentTimeMillis() - this.startTime) + : (this.stopTime - this.startTime); + return duration == 0 ? 0 : (double) this.writeMessageTotalSize.get() * 1000 / duration; + } + + public void statisticsAccept() { + if (!this.started) { + return; + } + this.acceptCount.incrementAndGet(); + } } diff --git a/src/main/java/com/google/code/yanf4j/statistics/package.html b/src/main/java/com/google/code/yanf4j/statistics/package.html index 45e751f19..0376a11cb 100644 --- a/src/main/java/com/google/code/yanf4j/statistics/package.html +++ b/src/main/java/com/google/code/yanf4j/statistics/package.html @@ -1,14 +1,10 @@ - - + - -Statistics - - - -

Networking statistics

- - - + + Statistics + + +

Networking statistics

+ + \ No newline at end of file diff --git a/src/main/java/com/google/code/yanf4j/util/ByteBufferMatcher.java b/src/main/java/com/google/code/yanf4j/util/ByteBufferMatcher.java index 1d6425f9c..fdf2e4c7a 100644 --- a/src/main/java/com/google/code/yanf4j/util/ByteBufferMatcher.java +++ b/src/main/java/com/google/code/yanf4j/util/ByteBufferMatcher.java @@ -1,29 +1,22 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.util; import java.util.List; - import com.google.code.yanf4j.buffer.IoBuffer; /** @@ -34,8 +27,8 @@ */ public interface ByteBufferMatcher { - public int matchFirst(IoBuffer buffer); + public int matchFirst(IoBuffer buffer); - public List matchAll(final IoBuffer buffer); + public List matchAll(final IoBuffer buffer); -} \ No newline at end of file +} diff --git a/src/main/java/com/google/code/yanf4j/util/ByteBufferUtils.java b/src/main/java/com/google/code/yanf4j/util/ByteBufferUtils.java index f2cda1f7b..965467bbc 100644 --- a/src/main/java/com/google/code/yanf4j/util/ByteBufferUtils.java +++ b/src/main/java/com/google/code/yanf4j/util/ByteBufferUtils.java @@ -1,213 +1,197 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.util; /* * Copyright 2004-2005 the original author or authors. - * - * Licensed 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. + * + * Licensed 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. */ /** * 来自于cindy2.4的工具类,做了简化和新增 */ import java.nio.ByteBuffer; - import com.google.code.yanf4j.config.Configuration; public class ByteBufferUtils { - /** - * - * @param byteBuffer - * @return * - */ - public static final ByteBuffer increaseBufferCapatity( - ByteBuffer byteBuffer) { + /** + * + * @param byteBuffer + * @return * + */ + public static final ByteBuffer increaseBufferCapatity(ByteBuffer byteBuffer) { - if (byteBuffer == null) { - throw new IllegalArgumentException("buffer is null"); - } - if (Configuration.DEFAULT_INCREASE_BUFF_SIZE < 0) { - throw new IllegalArgumentException("size less than 0"); - } + if (byteBuffer == null) { + throw new IllegalArgumentException("buffer is null"); + } + if (Configuration.DEFAULT_INCREASE_BUFF_SIZE < 0) { + throw new IllegalArgumentException("size less than 0"); + } - int capacity = byteBuffer.capacity() - + Configuration.DEFAULT_INCREASE_BUFF_SIZE; - if (capacity < 0) { - throw new IllegalArgumentException("capacity can't be negative"); - } - ByteBuffer result = (byteBuffer.isDirect() - ? ByteBuffer.allocateDirect(capacity) - : ByteBuffer.allocate(capacity)); - result.order(byteBuffer.order()); - byteBuffer.flip(); - result.put(byteBuffer); - return result; - } + int capacity = byteBuffer.capacity() + Configuration.DEFAULT_INCREASE_BUFF_SIZE; + if (capacity < 0) { + throw new IllegalArgumentException("capacity can't be negative"); + } + ByteBuffer result = (byteBuffer.isDirect() ? ByteBuffer.allocateDirect(capacity) + : ByteBuffer.allocate(capacity)); + result.order(byteBuffer.order()); + byteBuffer.flip(); + result.put(byteBuffer); + return result; + } - public static final void flip(ByteBuffer[] buffers) { - if (buffers == null) { - return; - } - for (ByteBuffer buffer : buffers) { - if (buffer != null) { - buffer.flip(); - } - } - } + public static final void flip(ByteBuffer[] buffers) { + if (buffers == null) { + return; + } + for (ByteBuffer buffer : buffers) { + if (buffer != null) { + buffer.flip(); + } + } + } - public static final ByteBuffer gather(ByteBuffer[] buffers) { - if (buffers == null || buffers.length == 0) { - return null; - } - ByteBuffer result = ByteBuffer.allocate(remaining(buffers)); - result.order(buffers[0].order()); - for (int i = 0; i < buffers.length; i++) { - if (buffers[i] != null) { - result.put(buffers[i]); - } - } - result.flip(); - return result; - } + public static final ByteBuffer gather(ByteBuffer[] buffers) { + if (buffers == null || buffers.length == 0) { + return null; + } + ByteBuffer result = ByteBuffer.allocate(remaining(buffers)); + result.order(buffers[0].order()); + for (int i = 0; i < buffers.length; i++) { + if (buffers[i] != null) { + result.put(buffers[i]); + } + } + result.flip(); + return result; + } - public static final int remaining(ByteBuffer[] buffers) { - if (buffers == null) { - return 0; - } - int remaining = 0; - for (int i = 0; i < buffers.length; i++) { - if (buffers[i] != null) { - remaining += buffers[i].remaining(); - } - } - return remaining; - } + public static final int remaining(ByteBuffer[] buffers) { + if (buffers == null) { + return 0; + } + int remaining = 0; + for (int i = 0; i < buffers.length; i++) { + if (buffers[i] != null) { + remaining += buffers[i].remaining(); + } + } + return remaining; + } - public static final void clear(ByteBuffer[] buffers) { - if (buffers == null) { - return; - } - for (ByteBuffer buffer : buffers) { - if (buffer != null) { - buffer.clear(); - } - } - } + public static final void clear(ByteBuffer[] buffers) { + if (buffers == null) { + return; + } + for (ByteBuffer buffer : buffers) { + if (buffer != null) { + buffer.clear(); + } + } + } - public static final String toHex(byte b) { - return ("" + "0123456789ABCDEF".charAt(0xf & b >> 4) - + "0123456789ABCDEF".charAt(b & 0xf)); - } + public static final String toHex(byte b) { + return ("" + "0123456789ABCDEF".charAt(0xf & b >> 4) + "0123456789ABCDEF".charAt(b & 0xf)); + } - public static final int indexOf(ByteBuffer buffer, ByteBuffer pattern) { - if (pattern == null || buffer == null) { - return -1; - } - int n = buffer.remaining(); - int m = pattern.remaining(); - int patternPos = pattern.position(); - int bufferPos = buffer.position(); - if (n < m) { - return -1; - } - for (int s = 0; s <= n - m; s++) { - boolean match = true; - for (int i = 0; i < m; i++) { - if (buffer.get(s + i + bufferPos) != pattern - .get(patternPos + i)) { - match = false; - break; - } - } - if (match) { - return (bufferPos + s); - } - } - return -1; - } + public static final int indexOf(ByteBuffer buffer, ByteBuffer pattern) { + if (pattern == null || buffer == null) { + return -1; + } + int n = buffer.remaining(); + int m = pattern.remaining(); + int patternPos = pattern.position(); + int bufferPos = buffer.position(); + if (n < m) { + return -1; + } + for (int s = 0; s <= n - m; s++) { + boolean match = true; + for (int i = 0; i < m; i++) { + if (buffer.get(s + i + bufferPos) != pattern.get(patternPos + i)) { + match = false; + break; + } + } + if (match) { + return (bufferPos + s); + } + } + return -1; + } - public static final int indexOf(ByteBuffer buffer, ByteBuffer pattern, - int offset) { - if (offset < 0) { - throw new IllegalArgumentException("offset must be greater than 0"); - } - if (pattern == null || buffer == null) { - return -1; - } - int patternPos = pattern.position(); - int n = buffer.remaining(); - int m = pattern.remaining(); - if (n < m) { - return -1; - } - if (offset < buffer.position() || offset > buffer.limit()) { - return -1; - } - for (int s = 0; s <= n - m; s++) { - boolean match = true; - for (int i = 0; i < m; i++) { - if (buffer.get(s + i + offset) != pattern.get(patternPos + i)) { - match = false; - break; - } - } - if (match) { - return (offset + s); - } - } - return -1; - } + public static final int indexOf(ByteBuffer buffer, ByteBuffer pattern, int offset) { + if (offset < 0) { + throw new IllegalArgumentException("offset must be greater than 0"); + } + if (pattern == null || buffer == null) { + return -1; + } + int patternPos = pattern.position(); + int n = buffer.remaining(); + int m = pattern.remaining(); + if (n < m) { + return -1; + } + if (offset < buffer.position() || offset > buffer.limit()) { + return -1; + } + for (int s = 0; s <= n - m; s++) { + boolean match = true; + for (int i = 0; i < m; i++) { + if (buffer.get(s + i + offset) != pattern.get(patternPos + i)) { + match = false; + break; + } + } + if (match) { + return (offset + s); + } + } + return -1; + } - /** - * 查看ByteBuffer数组是否还有剩余 - * - * @param buffers - * ByteBuffers - * @return have remaining - */ - public static final boolean hasRemaining(ByteBuffer[] buffers) { - if (buffers == null) { - return false; - } - for (int i = 0; i < buffers.length; i++) { - if (buffers[i] != null && buffers[i].hasRemaining()) { - return true; - } - } - return false; - } + /** + * 查看ByteBuffer数组是否还有剩余 + * + * @param buffers ByteBuffers + * @return have remaining + */ + public static final boolean hasRemaining(ByteBuffer[] buffers) { + if (buffers == null) { + return false; + } + for (int i = 0; i < buffers.length; i++) { + if (buffers[i] != null && buffers[i].hasRemaining()) { + return true; + } + } + return false; + } - public static final int uByte(byte b) { - return b & 0xFF; - } + public static final int uByte(byte b) { + return b & 0xFF; + } } diff --git a/src/main/java/com/google/code/yanf4j/util/CircularQueue.java b/src/main/java/com/google/code/yanf4j/util/CircularQueue.java index 37d4b6abc..1843da7bc 100644 --- a/src/main/java/com/google/code/yanf4j/util/CircularQueue.java +++ b/src/main/java/com/google/code/yanf4j/util/CircularQueue.java @@ -1,361 +1,342 @@ -package com.google.code.yanf4j.util; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -import java.io.Serializable; -import java.util.AbstractList; -import java.util.Arrays; -import java.util.List; -import java.util.NoSuchElementException; -import java.util.Queue; - -/** - * A circular queue from mina - * - * @author dennis - * - * @param - */ -public class CircularQueue extends AbstractList - implements - List, - Queue, - Serializable { - - private static final long serialVersionUID = 3993421269224511264L; - - private static final int DEFAULT_CAPACITY = 4; - - private final int initialCapacity; - // XXX: This volatile keyword here is a workaround for SUN Java Compiler - // bug, - // which produces buggy byte code. I don't event know why adding a volatile - // fixes the problem. Eclipse Java Compiler seems to produce correct byte - // code. - private volatile Object[] items; - private int mask; - private int first = 0; - private int last = 0; - private boolean full; - private int shrinkThreshold; - - /** - * Construct a new, empty queue. - */ - public CircularQueue() { - this(DEFAULT_CAPACITY); - } - - public CircularQueue(int initialCapacity) { - int actualCapacity = normalizeCapacity(initialCapacity); - this.items = new Object[actualCapacity]; - this.mask = actualCapacity - 1; - this.initialCapacity = actualCapacity; - this.shrinkThreshold = 0; - } - - private static int normalizeCapacity(int initialCapacity) { - int actualCapacity = 1; - while (actualCapacity < initialCapacity) { - actualCapacity <<= 1; - if (actualCapacity < 0) { - actualCapacity = 1 << 30; - break; - } - } - return actualCapacity; - } - - /** - * Returns the capacity of this queue. - */ - public int capacity() { - return this.items.length; - } - - @Override - public void clear() { - if (!isEmpty()) { - Arrays.fill(this.items, null); - this.first = 0; - this.last = 0; - this.full = false; - shrinkIfNeeded(); - } - } - - @SuppressWarnings("unchecked") - public E poll() { - if (isEmpty()) { - return null; - } - - Object ret = this.items[this.first]; - this.items[this.first] = null; - decreaseSize(); - - if (this.first == this.last) { - this.first = this.last = 0; - } - - shrinkIfNeeded(); - return (E) ret; - } - - public boolean offer(E item) { - if (item == null) { - throw new NullPointerException("item"); - } - expandIfNeeded(); - this.items[this.last] = item; - increaseSize(); - return true; - } - - @SuppressWarnings("unchecked") - public E peek() { - if (isEmpty()) { - return null; - } - - return (E) this.items[this.first]; - } - - @SuppressWarnings("unchecked") - @Override - public E get(int idx) { - checkIndex(idx); - return (E) this.items[getRealIndex(idx)]; - } - - @Override - public boolean isEmpty() { - return (this.first == this.last) && !this.full; - } - - @Override - public int size() { - if (this.full) { - return capacity(); - } - - if (this.last >= this.first) { - return this.last - this.first; - } else { - return this.last - this.first + capacity(); - } - } - - @Override - public String toString() { - return "first=" + this.first + ", last=" + this.last + ", size=" - + size() + ", mask = " + this.mask; - } - - private void checkIndex(int idx) { - if (idx < 0 || idx >= size()) { - throw new IndexOutOfBoundsException(String.valueOf(idx)); - } - } - - private int getRealIndex(int idx) { - return (this.first + idx) & this.mask; - } - - private void increaseSize() { - this.last = (this.last + 1) & this.mask; - this.full = this.first == this.last; - } - - private void decreaseSize() { - this.first = (this.first + 1) & this.mask; - this.full = false; - } - - private void expandIfNeeded() { - if (this.full) { - // expand queue - final int oldLen = this.items.length; - final int newLen = oldLen << 1; - Object[] tmp = new Object[newLen]; - - if (this.first < this.last) { - System.arraycopy(this.items, this.first, tmp, 0, - this.last - this.first); - } else { - System.arraycopy(this.items, this.first, tmp, 0, - oldLen - this.first); - System.arraycopy(this.items, 0, tmp, oldLen - this.first, - this.last); - } - - this.first = 0; - this.last = oldLen; - this.items = tmp; - this.mask = tmp.length - 1; - if (newLen >>> 3 > this.initialCapacity) { - this.shrinkThreshold = newLen >>> 3; - } - } - } - - private void shrinkIfNeeded() { - int size = size(); - if (size <= this.shrinkThreshold) { - // shrink queue - final int oldLen = this.items.length; - int newLen = normalizeCapacity(size); - if (size == newLen) { - newLen <<= 1; - } - - if (newLen >= oldLen) { - return; - } - - if (newLen < this.initialCapacity) { - if (oldLen == this.initialCapacity) { - return; - } else { - newLen = this.initialCapacity; - } - } - - Object[] tmp = new Object[newLen]; - - // Copy only when there's something to copy. - if (size > 0) { - if (this.first < this.last) { - System.arraycopy(this.items, this.first, tmp, 0, - this.last - this.first); - } else { - System.arraycopy(this.items, this.first, tmp, 0, - oldLen - this.first); - System.arraycopy(this.items, 0, tmp, oldLen - this.first, - this.last); - } - } - - this.first = 0; - this.last = size; - this.items = tmp; - this.mask = tmp.length - 1; - this.shrinkThreshold = 0; - } - } - - @Override - public boolean add(E o) { - return offer(o); - } - - @SuppressWarnings("unchecked") - @Override - public E set(int idx, E o) { - checkIndex(idx); - - int realIdx = getRealIndex(idx); - Object old = this.items[realIdx]; - this.items[realIdx] = o; - return (E) old; - } - - @Override - public void add(int idx, E o) { - if (idx == size()) { - offer(o); - return; - } - - checkIndex(idx); - expandIfNeeded(); - - int realIdx = getRealIndex(idx); - - // Make a room for a new element. - if (this.first < this.last) { - System.arraycopy(this.items, realIdx, this.items, realIdx + 1, - this.last - realIdx); - } else { - if (realIdx >= this.first) { - System.arraycopy(this.items, 0, this.items, 1, this.last); - this.items[0] = this.items[this.items.length - 1]; - System.arraycopy(this.items, realIdx, this.items, realIdx + 1, - this.items.length - realIdx - 1); - } else { - System.arraycopy(this.items, realIdx, this.items, realIdx + 1, - this.last - realIdx); - } - } - - this.items[realIdx] = o; - increaseSize(); - } - - @SuppressWarnings("unchecked") - @Override - public E remove(int idx) { - if (idx == 0) { - return poll(); - } - - checkIndex(idx); - - int realIdx = getRealIndex(idx); - Object removed = this.items[realIdx]; - - // Remove a room for the removed element. - if (this.first < this.last) { - System.arraycopy(this.items, this.first, this.items, this.first + 1, - realIdx - this.first); - } else { - if (realIdx >= this.first) { - System.arraycopy(this.items, this.first, this.items, - this.first + 1, realIdx - this.first); - } else { - System.arraycopy(this.items, 0, this.items, 1, realIdx); - this.items[0] = this.items[this.items.length - 1]; - System.arraycopy(this.items, this.first, this.items, - this.first + 1, this.items.length - this.first - 1); - } - } - - this.items[this.first] = null; - decreaseSize(); - - shrinkIfNeeded(); - return (E) removed; - } - - public E remove() { - if (isEmpty()) { - throw new NoSuchElementException(); - } - return poll(); - } - - public E element() { - if (isEmpty()) { - throw new NoSuchElementException(); - } - return peek(); - } -} +package com.google.code.yanf4j.util; + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF 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. + */ + +import java.io.Serializable; +import java.util.AbstractList; +import java.util.Arrays; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Queue; + +/** + * A circular queue from mina + * + * @author dennis + * + * @param + */ +public class CircularQueue extends AbstractList implements List, Queue, Serializable { + + private static final long serialVersionUID = 3993421269224511264L; + + private static final int DEFAULT_CAPACITY = 4; + + private final int initialCapacity; + // XXX: This volatile keyword here is a workaround for SUN Java Compiler + // bug, + // which produces buggy byte code. I don't event know why adding a volatile + // fixes the problem. Eclipse Java Compiler seems to produce correct byte + // code. + private volatile Object[] items; + private int mask; + private int first = 0; + private int last = 0; + private boolean full; + private int shrinkThreshold; + + /** + * Construct a new, empty queue. + */ + public CircularQueue() { + this(DEFAULT_CAPACITY); + } + + public CircularQueue(int initialCapacity) { + int actualCapacity = normalizeCapacity(initialCapacity); + this.items = new Object[actualCapacity]; + this.mask = actualCapacity - 1; + this.initialCapacity = actualCapacity; + this.shrinkThreshold = 0; + } + + private static int normalizeCapacity(int initialCapacity) { + int actualCapacity = 1; + while (actualCapacity < initialCapacity) { + actualCapacity <<= 1; + if (actualCapacity < 0) { + actualCapacity = 1 << 30; + break; + } + } + return actualCapacity; + } + + /** + * Returns the capacity of this queue. + */ + public int capacity() { + return this.items.length; + } + + @Override + public void clear() { + if (!isEmpty()) { + Arrays.fill(this.items, null); + this.first = 0; + this.last = 0; + this.full = false; + shrinkIfNeeded(); + } + } + + @SuppressWarnings("unchecked") + public E poll() { + if (isEmpty()) { + return null; + } + + Object ret = this.items[this.first]; + this.items[this.first] = null; + decreaseSize(); + + if (this.first == this.last) { + this.first = this.last = 0; + } + + shrinkIfNeeded(); + return (E) ret; + } + + public boolean offer(E item) { + if (item == null) { + throw new NullPointerException("item"); + } + expandIfNeeded(); + this.items[this.last] = item; + increaseSize(); + return true; + } + + @SuppressWarnings("unchecked") + public E peek() { + if (isEmpty()) { + return null; + } + + return (E) this.items[this.first]; + } + + @SuppressWarnings("unchecked") + @Override + public E get(int idx) { + checkIndex(idx); + return (E) this.items[getRealIndex(idx)]; + } + + @Override + public boolean isEmpty() { + return (this.first == this.last) && !this.full; + } + + @Override + public int size() { + if (this.full) { + return capacity(); + } + + if (this.last >= this.first) { + return this.last - this.first; + } else { + return this.last - this.first + capacity(); + } + } + + @Override + public String toString() { + return "first=" + this.first + ", last=" + this.last + ", size=" + size() + ", mask = " + + this.mask; + } + + private void checkIndex(int idx) { + if (idx < 0 || idx >= size()) { + throw new IndexOutOfBoundsException(String.valueOf(idx)); + } + } + + private int getRealIndex(int idx) { + return (this.first + idx) & this.mask; + } + + private void increaseSize() { + this.last = (this.last + 1) & this.mask; + this.full = this.first == this.last; + } + + private void decreaseSize() { + this.first = (this.first + 1) & this.mask; + this.full = false; + } + + private void expandIfNeeded() { + if (this.full) { + // expand queue + final int oldLen = this.items.length; + final int newLen = oldLen << 1; + Object[] tmp = new Object[newLen]; + + if (this.first < this.last) { + System.arraycopy(this.items, this.first, tmp, 0, this.last - this.first); + } else { + System.arraycopy(this.items, this.first, tmp, 0, oldLen - this.first); + System.arraycopy(this.items, 0, tmp, oldLen - this.first, this.last); + } + + this.first = 0; + this.last = oldLen; + this.items = tmp; + this.mask = tmp.length - 1; + if (newLen >>> 3 > this.initialCapacity) { + this.shrinkThreshold = newLen >>> 3; + } + } + } + + private void shrinkIfNeeded() { + int size = size(); + if (size <= this.shrinkThreshold) { + // shrink queue + final int oldLen = this.items.length; + int newLen = normalizeCapacity(size); + if (size == newLen) { + newLen <<= 1; + } + + if (newLen >= oldLen) { + return; + } + + if (newLen < this.initialCapacity) { + if (oldLen == this.initialCapacity) { + return; + } else { + newLen = this.initialCapacity; + } + } + + Object[] tmp = new Object[newLen]; + + // Copy only when there's something to copy. + if (size > 0) { + if (this.first < this.last) { + System.arraycopy(this.items, this.first, tmp, 0, this.last - this.first); + } else { + System.arraycopy(this.items, this.first, tmp, 0, oldLen - this.first); + System.arraycopy(this.items, 0, tmp, oldLen - this.first, this.last); + } + } + + this.first = 0; + this.last = size; + this.items = tmp; + this.mask = tmp.length - 1; + this.shrinkThreshold = 0; + } + } + + @Override + public boolean add(E o) { + return offer(o); + } + + @SuppressWarnings("unchecked") + @Override + public E set(int idx, E o) { + checkIndex(idx); + + int realIdx = getRealIndex(idx); + Object old = this.items[realIdx]; + this.items[realIdx] = o; + return (E) old; + } + + @Override + public void add(int idx, E o) { + if (idx == size()) { + offer(o); + return; + } + + checkIndex(idx); + expandIfNeeded(); + + int realIdx = getRealIndex(idx); + + // Make a room for a new element. + if (this.first < this.last) { + System.arraycopy(this.items, realIdx, this.items, realIdx + 1, this.last - realIdx); + } else { + if (realIdx >= this.first) { + System.arraycopy(this.items, 0, this.items, 1, this.last); + this.items[0] = this.items[this.items.length - 1]; + System.arraycopy(this.items, realIdx, this.items, realIdx + 1, + this.items.length - realIdx - 1); + } else { + System.arraycopy(this.items, realIdx, this.items, realIdx + 1, this.last - realIdx); + } + } + + this.items[realIdx] = o; + increaseSize(); + } + + @SuppressWarnings("unchecked") + @Override + public E remove(int idx) { + if (idx == 0) { + return poll(); + } + + checkIndex(idx); + + int realIdx = getRealIndex(idx); + Object removed = this.items[realIdx]; + + // Remove a room for the removed element. + if (this.first < this.last) { + System.arraycopy(this.items, this.first, this.items, this.first + 1, realIdx - this.first); + } else { + if (realIdx >= this.first) { + System.arraycopy(this.items, this.first, this.items, this.first + 1, realIdx - this.first); + } else { + System.arraycopy(this.items, 0, this.items, 1, realIdx); + this.items[0] = this.items[this.items.length - 1]; + System.arraycopy(this.items, this.first, this.items, this.first + 1, + this.items.length - this.first - 1); + } + } + + this.items[this.first] = null; + decreaseSize(); + + shrinkIfNeeded(); + return (E) removed; + } + + public E remove() { + if (isEmpty()) { + throw new NoSuchElementException(); + } + return poll(); + } + + public E element() { + if (isEmpty()) { + throw new NoSuchElementException(); + } + return peek(); + } +} diff --git a/src/main/java/com/google/code/yanf4j/util/ConcurrentHashSet.java b/src/main/java/com/google/code/yanf4j/util/ConcurrentHashSet.java index fc300d436..e0cdf4655 100644 --- a/src/main/java/com/google/code/yanf4j/util/ConcurrentHashSet.java +++ b/src/main/java/com/google/code/yanf4j/util/ConcurrentHashSet.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.util; @@ -31,25 +25,23 @@ * A {@link ConcurrentHashMap}-backed {@link Set}. * * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev: 597692 $, $Date: 2007-11-23 08:56:32 -0700 (Fri, 23 Nov 2007) - * $ + * @version $Rev: 597692 $, $Date: 2007-11-23 08:56:32 -0700 (Fri, 23 Nov 2007) $ */ public class ConcurrentHashSet extends MapBackedSet { - private static final long serialVersionUID = 8518578988740277828L; + private static final long serialVersionUID = 8518578988740277828L; - public ConcurrentHashSet() { - super(new ConcurrentHashMap()); - } + public ConcurrentHashSet() { + super(new ConcurrentHashMap()); + } - public ConcurrentHashSet(Collection c) { - super(new ConcurrentHashMap(), c); - } + public ConcurrentHashSet(Collection c) { + super(new ConcurrentHashMap(), c); + } - @Override - public boolean add(E o) { - Boolean answer = ((ConcurrentMap) map).putIfAbsent(o, - Boolean.TRUE); - return answer == null; - } + @Override + public boolean add(E o) { + Boolean answer = ((ConcurrentMap) map).putIfAbsent(o, Boolean.TRUE); + return answer == null; + } } diff --git a/src/main/java/com/google/code/yanf4j/util/DispatcherFactory.java b/src/main/java/com/google/code/yanf4j/util/DispatcherFactory.java index 26c0d2d76..1453a37b9 100644 --- a/src/main/java/com/google/code/yanf4j/util/DispatcherFactory.java +++ b/src/main/java/com/google/code/yanf4j/util/DispatcherFactory.java @@ -2,7 +2,6 @@ import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.TimeUnit; - import com.google.code.yanf4j.core.impl.PoolDispatcher; /** @@ -12,13 +11,12 @@ * */ public class DispatcherFactory { - public static com.google.code.yanf4j.core.Dispatcher newDispatcher(int size, - RejectedExecutionHandler rejectedExecutionHandler, String prefix) { - if (size > 0) { - return new PoolDispatcher(size, 60, TimeUnit.SECONDS, - rejectedExecutionHandler, prefix); - } else { - return null; - } - } + public static com.google.code.yanf4j.core.Dispatcher newDispatcher(int size, + RejectedExecutionHandler rejectedExecutionHandler, String prefix) { + if (size > 0) { + return new PoolDispatcher(size, 60, TimeUnit.SECONDS, rejectedExecutionHandler, prefix); + } else { + return null; + } + } } diff --git a/src/main/java/com/google/code/yanf4j/util/LinkedTransferQueue.java b/src/main/java/com/google/code/yanf4j/util/LinkedTransferQueue.java index c3725fb79..829cca2d0 100644 --- a/src/main/java/com/google/code/yanf4j/util/LinkedTransferQueue.java +++ b/src/main/java/com/google/code/yanf4j/util/LinkedTransferQueue.java @@ -1,827 +1,780 @@ -/* -* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. -* -* Copyright 1997-2008 Sun Microsystems, Inc. All rights reserved. -* -* The contents of this file are subject to the terms of either the GNU -* General Public License Version 2 only ("GPL") or the Common Development -* and Distribution License("CDDL") (collectively, the "License"). You -* may not use this file except in compliance with the License. You can obtain -* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html -* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific -* language governing permissions and limitations under the License. -* -* When distributing the software, include this License Header Notice in each -* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt. -* Sun designates this particular file as subject to the "Classpath" exception -* as provided by Sun in the GPL Version 2 section of the License file that -* accompanied this code. If applicable, add the following below the License -* Header, with the fields enclosed by brackets [] replaced by your own -* identifying information: "Portions Copyrighted [year] -* [name of copyright owner]" -* -* Contributor(s): -* -* If you wish your version of this file to be governed by only the CDDL or -* only the GPL Version 2, indicate your decision by adding "[Contributor] -* elects to include this software in this distribution under the [CDDL or GPL -* Version 2] license." If you don't indicate a single choice of license, a -* recipient has the option to distribute your version of this file under -* either the CDDL, the GPL Version 2 or to extend the choice of license to -* its licensees as provided above. However, if you add GPL Version 2 code -* and therefore, elected the GPL Version 2 license, then the option applies -* only if the new code is made subject to such option by the copyright -* holder. -*/ - -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package com.google.code.yanf4j.util; - -import java.util.AbstractQueue; -import java.util.Collection; -import java.util.Iterator; -import java.util.NoSuchElementException; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; -import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; -import java.util.concurrent.locks.LockSupport; - -/** - * An unbounded TransferQueue based on linked nodes. This queue orders - * elements FIFO (first-in-first-out) with respect to any given producer. The - * head of the queue is that element that has been on the queue the - * longest time for some producer. The tail of the queue is that - * element that has been on the queue the shortest time for some producer. - * - *

- * Beware that, unlike in most collections, the size method is - * NOT a constant-time operation. Because of the asynchronous nature of - * these queues, determining the current number of elements requires a traversal - * of the elements. - * - *

- * This class and its iterator implement all of the optional methods of - * the {@link Collection} and {@link Iterator} interfaces. - * - *

- * Memory consistency effects: As with other concurrent collections, actions in - * a thread prior to placing an object into a {@code LinkedTransferQueue} - * happen-before - * actions subsequent to the access or removal of that element from the - * {@code LinkedTransferQueue} in another thread. - * - * @author Doug Lea - * @author The Netty Project (netty-dev@lists.jboss.org) - * @author Trustin Lee (tlee@redhat.com) - * - * @param - * the type of elements held in this collection - * - */ -public class LinkedTransferQueue extends AbstractQueue - implements - BlockingQueue { - - /* - * This class extends the approach used in FIFO-mode SynchronousQueues. See - * the internal documentation, as well as the PPoPP 2006 paper - * "Scalable Synchronous Queues" by Scherer, Lea & Scott - * (http://www.cs.rice.edu/~wns1/papers/2006-PPoPP-SQ.pdf) - * - * The main extension is to provide different Wait modes for the main "xfer" - * method that puts or takes items. These don't impact the basic dual-queue - * logic, but instead control whether or how threads block upon insertion of - * request or data nodes into the dual queue. It also uses slightly - * different conventions for tracking whether nodes are off-list or - * cancelled. - */ - - // Wait modes for xfer method - private static final int NOWAIT = 0; - private static final int TIMEOUT = 1; - private static final int WAIT = 2; - - /** The number of CPUs, for spin control */ - private static final int NCPUS = Runtime.getRuntime().availableProcessors(); - - /** - * The number of times to spin before blocking in timed waits. The value is - * empirically derived -- it works well across a variety of processors and - * OSes. Empirically, the best value seems not to vary with number of CPUs - * (beyond 2) so is just a constant. - */ - private static final int maxTimedSpins = NCPUS < 2 ? 0 : 32; - - /** - * The number of times to spin before blocking in untimed waits. This is - * greater than timed value because untimed waits spin faster since they - * don't need to check times on each spin. - */ - private static final int maxUntimedSpins = maxTimedSpins * 16; - - /** - * The number of nanoseconds for which it is faster to spin rather than to - * use timed park. A rough estimate suffices. - */ - private static final long spinForTimeoutThreshold = 1000L; - - /** - * Node class for LinkedTransferQueue. Opportunistically subclasses from - * AtomicReference to represent item. Uses Object, not E, to allow setting - * item to "this" after use, to avoid garbage retention. Similarly, setting - * the next field to this is used as sentinel that node is off list. - */ - private static final class QNode extends AtomicReference { - private static final long serialVersionUID = 5925596372370723938L; - - transient volatile QNode next; - transient volatile Thread waiter; // to control park/unpark - final boolean isData; - public long p1, p2, p3, p4, p5, p6, p7; - QNode(Object item, boolean isData) { - super(item); - this.isData = isData; - } - - private static final AtomicReferenceFieldUpdater nextUpdater; - static { - AtomicReferenceFieldUpdater tmp = null; - try { - tmp = AtomicReferenceFieldUpdater.newUpdater(QNode.class, - QNode.class, "next"); - - // Test if AtomicReferenceFieldUpdater is really working. - QNode testNode = new QNode(null, false); - tmp.set(testNode, testNode); - if (testNode.next != testNode) { - // Not set as expected - fall back to the safe mode. - throw new Exception(); - } - } catch (Throwable t) { - // Running in a restricted environment with a security manager. - tmp = null; - } - nextUpdater = tmp; - } - - boolean casNext(QNode cmp, QNode val) { - if (nextUpdater != null) { - return nextUpdater.compareAndSet(this, cmp, val); - } else { - return alternativeCasNext(cmp, val); - } - } - - private synchronized boolean alternativeCasNext(QNode cmp, QNode val) { - if (this.next == cmp) { - this.next = val; - return true; - } else { - return false; - } - } - } - - /** - * Padded version of AtomicReference used for head, tail and cleanMe, to - * alleviate contention across threads CASing one vs the other. - */ - public static final class PaddedAtomicReference - extends - AtomicReference { - private static final long serialVersionUID = 4684288940772921317L; - - // enough padding for 64bytes with 4byte refs - @SuppressWarnings("unused") - public Object p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, - pe; - public PaddedAtomicReference(T r) { - super(r); - } - } - - /** head of the queue */ - private final PaddedAtomicReference head; - /** tail of the queue */ - private final PaddedAtomicReference tail; - - /** - * Reference to a cancelled node that might not yet have been unlinked from - * queue because it was the last inserted node when it cancelled. - */ - private final PaddedAtomicReference cleanMe; - - /** - * Tries to cas nh as new head; if successful, unlink old head's next node - * to avoid garbage retention. - */ - private boolean advanceHead(QNode h, QNode nh) { - if (h == this.head.get() && this.head.compareAndSet(h, nh)) { - h.next = h; // forget old next - return true; - } - return false; - } - - /** - * Puts or takes an item. Used for most queue operations (except poll() and - * tryTransfer()). See the similar code in SynchronousQueue for detailed - * explanation. - * - * @param e - * the item or if null, signifies that this is a take - * @param mode - * the wait mode: NOWAIT, TIMEOUT, WAIT - * @param nanos - * timeout in nanosecs, used only if mode is TIMEOUT - * @return an item, or null on failure - */ - private Object xfer(Object e, int mode, long nanos) { - boolean isData = e != null; - QNode s = null; - final PaddedAtomicReference head = this.head; - final PaddedAtomicReference tail = this.tail; - - for (;;) { - QNode t = tail.get(); - QNode h = head.get(); - - if (t != null && (t == h || t.isData == isData)) { - if (s == null) { - s = new QNode(e, isData); - } - QNode last = t.next; - if (last != null) { - if (t == tail.get()) { - tail.compareAndSet(t, last); - } - } else if (t.casNext(null, s)) { - tail.compareAndSet(t, s); - return awaitFulfill(t, s, e, mode, nanos); - } - } - - else if (h != null) { - QNode first = h.next; - if (t == tail.get() && first != null && advanceHead(h, first)) { - Object x = first.get(); - if (x != first && first.compareAndSet(x, e)) { - LockSupport.unpark(first.waiter); - return isData ? e : x; - } - } - } - } - } - - /** - * Version of xfer for poll() and tryTransfer, which simplifies control - * paths both here and in xfer - */ - private Object fulfill(Object e) { - boolean isData = e != null; - final PaddedAtomicReference head = this.head; - final PaddedAtomicReference tail = this.tail; - - for (;;) { - QNode t = tail.get(); - QNode h = head.get(); - - if (t != null && (t == h || t.isData == isData)) { - QNode last = t.next; - if (t == tail.get()) { - if (last != null) { - tail.compareAndSet(t, last); - } else { - return null; - } - } - } else if (h != null) { - QNode first = h.next; - if (t == tail.get() && first != null && advanceHead(h, first)) { - Object x = first.get(); - if (x != first && first.compareAndSet(x, e)) { - LockSupport.unpark(first.waiter); - return isData ? e : x; - } - } - } - } - } - - /** - * Spins/blocks until node s is fulfilled or caller gives up, depending on - * wait mode. - * - * @param pred - * the predecessor of waiting node - * @param s - * the waiting node - * @param e - * the comparison value for checking match - * @param mode - * mode - * @param nanos - * timeout value - * @return matched item, or s if cancelled - */ - private Object awaitFulfill(QNode pred, QNode s, Object e, int mode, - long nanos) { - if (mode == NOWAIT) { - return null; - } - - long lastTime = mode == TIMEOUT ? System.nanoTime() : 0; - Thread w = Thread.currentThread(); - int spins = -1; // set to desired spin count below - for (;;) { - if (w.isInterrupted()) { - s.compareAndSet(e, s); - } - Object x = s.get(); - if (x != e) { // Node was matched or cancelled - advanceHead(pred, s); // unlink if head - if (x == s) { // was cancelled - clean(pred, s); - return null; - } else if (x != null) { - s.set(s); // avoid garbage retention - return x; - } else { - return e; - } - } - if (mode == TIMEOUT) { - long now = System.nanoTime(); - nanos -= now - lastTime; - lastTime = now; - if (nanos <= 0) { - s.compareAndSet(e, s); // try to cancel - continue; - } - } - if (spins < 0) { - QNode h = this.head.get(); // only spin if at head - spins = h != null && h.next == s - ? (mode == TIMEOUT ? maxTimedSpins : maxUntimedSpins) - : 0; - } - if (spins > 0) { - --spins; - } else if (s.waiter == null) { - s.waiter = w; - } else if (mode != TIMEOUT) { - // LockSupport.park(this); - LockSupport.park(); // allows run on java5 - s.waiter = null; - spins = -1; - } else if (nanos > spinForTimeoutThreshold) { - // LockSupport.parkNanos(this, nanos); - LockSupport.parkNanos(nanos); - s.waiter = null; - spins = -1; - } - } - } - - /** - * Returns validated tail for use in cleaning methods - */ - private QNode getValidatedTail() { - for (;;) { - QNode h = this.head.get(); - QNode first = h.next; - if (first != null && first.next == first) { // help advance - advanceHead(h, first); - continue; - } - QNode t = this.tail.get(); - QNode last = t.next; - if (t == this.tail.get()) { - if (last != null) { - this.tail.compareAndSet(t, last); // help advance - } else { - return t; - } - } - } - } - - /** - * Gets rid of cancelled node s with original predecessor pred. - * - * @param pred - * predecessor of cancelled node - * @param s - * the cancelled node - */ - void clean(QNode pred, QNode s) { - Thread w = s.waiter; - if (w != null) { // Wake up thread - s.waiter = null; - if (w != Thread.currentThread()) { - LockSupport.unpark(w); - } - } - /* - * At any given time, exactly one node on list cannot be deleted -- the - * last inserted node. To accommodate this, if we cannot delete s, we - * save its predecessor as "cleanMe", processing the previously saved - * version first. At least one of node s or the node previously saved - * can always be processed, so this always terminates. - */ - while (pred.next == s) { - QNode oldpred = reclean(); // First, help get rid of cleanMe - QNode t = getValidatedTail(); - if (s != t) { // If not tail, try to unsplice - QNode sn = s.next; // s.next == s means s already off list - if (sn == s || pred.casNext(s, sn)) { - break; - } - } else if (oldpred == pred || // Already saved - oldpred == null && this.cleanMe.compareAndSet(null, pred)) { - break; // Postpone cleaning - } - } - } - - /** - * Tries to unsplice the cancelled node held in cleanMe that was previously - * uncleanable because it was at tail. - * - * @return current cleanMe node (or null) - */ - private QNode reclean() { - /* - * cleanMe is, or at one time was, predecessor of cancelled node s that - * was the tail so could not be unspliced. If s is no longer the tail, - * try to unsplice if necessary and make cleanMe slot available. This - * differs from similar code in clean() because we must check that pred - * still points to a cancelled node that must be unspliced -- if not, we - * can (must) clear cleanMe without unsplicing. This can loop only due - * to contention on casNext or clearing cleanMe. - */ - QNode pred; - while ((pred = this.cleanMe.get()) != null) { - QNode t = getValidatedTail(); - QNode s = pred.next; - if (s != t) { - QNode sn; - if (s == null || s == pred || s.get() != s || (sn = s.next) == s - || pred.casNext(s, sn)) { - this.cleanMe.compareAndSet(pred, null); - } - } else { - break; - } - } - return pred; - } - - @SuppressWarnings("unchecked") - E cast(Object e) { - return (E) e; - } - - /** - * Creates an initially empty LinkedTransferQueue. - */ - public LinkedTransferQueue() { - QNode dummy = new QNode(null, false); - this.head = new PaddedAtomicReference(dummy); - this.tail = new PaddedAtomicReference(dummy); - this.cleanMe = new PaddedAtomicReference(null); - } - - /** - * Creates a LinkedTransferQueue initially containing the elements - * of the given collection, added in traversal order of the collection's - * iterator. - * - * @param c - * the collection of elements to initially contain - * @throws NullPointerException - * if the specified collection or any of its elements are null - */ - public LinkedTransferQueue(Collection c) { - this(); - addAll(c); - } - - public void put(E e) throws InterruptedException { - if (e == null) { - throw new NullPointerException(); - } - if (Thread.interrupted()) { - throw new InterruptedException(); - } - xfer(e, NOWAIT, 0); - } - - public boolean offer(E e, long timeout, TimeUnit unit) - throws InterruptedException { - if (e == null) { - throw new NullPointerException(); - } - if (Thread.interrupted()) { - throw new InterruptedException(); - } - xfer(e, NOWAIT, 0); - return true; - } - - public boolean offer(E e) { - if (e == null) { - throw new NullPointerException(); - } - xfer(e, NOWAIT, 0); - return true; - } - - public void transfer(E e) throws InterruptedException { - if (e == null) { - throw new NullPointerException(); - } - if (xfer(e, WAIT, 0) == null) { - Thread.interrupted(); - throw new InterruptedException(); - } - } - - public boolean tryTransfer(E e, long timeout, TimeUnit unit) - throws InterruptedException { - if (e == null) { - throw new NullPointerException(); - } - if (xfer(e, TIMEOUT, unit.toNanos(timeout)) != null) { - return true; - } - if (!Thread.interrupted()) { - return false; - } - throw new InterruptedException(); - } - - public boolean tryTransfer(E e) { - if (e == null) { - throw new NullPointerException(); - } - return fulfill(e) != null; - } - - public E take() throws InterruptedException { - Object e = xfer(null, WAIT, 0); - if (e != null) { - return cast(e); - } - Thread.interrupted(); - throw new InterruptedException(); - } - - public E poll(long timeout, TimeUnit unit) throws InterruptedException { - Object e = xfer(null, TIMEOUT, unit.toNanos(timeout)); - if (e != null || !Thread.interrupted()) { - return cast(e); - } - throw new InterruptedException(); - } - - public E poll() { - return cast(fulfill(null)); - } - - public int drainTo(Collection c) { - if (c == null) { - throw new NullPointerException(); - } - if (c == this) { - throw new IllegalArgumentException(); - } - int n = 0; - E e; - while ((e = poll()) != null) { - c.add(e); - ++n; - } - return n; - } - - public int drainTo(Collection c, int maxElements) { - if (c == null) { - throw new NullPointerException(); - } - if (c == this) { - throw new IllegalArgumentException(); - } - int n = 0; - E e; - while (n < maxElements && (e = poll()) != null) { - c.add(e); - ++n; - } - return n; - } - - // Traversal-based methods - - /** - * Return head after performing any outstanding helping steps - */ - QNode traversalHead() { - for (;;) { - QNode t = this.tail.get(); - QNode h = this.head.get(); - if (h != null && t != null) { - QNode last = t.next; - QNode first = h.next; - if (t == this.tail.get()) { - if (last != null) { - this.tail.compareAndSet(t, last); - } else if (first != null) { - Object x = first.get(); - if (x == first) { - advanceHead(h, first); - } else { - return h; - } - } else { - return h; - } - } - } - } - } - - @Override - public Iterator iterator() { - return new Itr(); - } - - /** - * Iterators. Basic strategy is to traverse list, treating non-data (i.e., - * request) nodes as terminating list. Once a valid data node is found, the - * item is cached so that the next call to next() will return it even if - * subsequently removed. - */ - class Itr implements Iterator { - QNode nextNode; // Next node to return next - QNode currentNode; // last returned node, for remove() - QNode prevNode; // predecessor of last returned node - E nextItem; // Cache of next item, once commited to in next - - Itr() { - this.nextNode = traversalHead(); - advance(); - } - - E advance() { - this.prevNode = this.currentNode; - this.currentNode = this.nextNode; - E x = this.nextItem; - - QNode p = this.nextNode.next; - for (;;) { - if (p == null || !p.isData) { - this.nextNode = null; - this.nextItem = null; - return x; - } - Object item = p.get(); - if (item != p && item != null) { - this.nextNode = p; - this.nextItem = cast(item); - return x; - } - this.prevNode = p; - p = p.next; - } - } - - public boolean hasNext() { - return this.nextNode != null; - } - - public E next() { - if (this.nextNode == null) { - throw new NoSuchElementException(); - } - return advance(); - } - - public void remove() { - QNode p = this.currentNode; - QNode prev = this.prevNode; - if (prev == null || p == null) { - throw new IllegalStateException(); - } - Object x = p.get(); - if (x != null && x != p && p.compareAndSet(x, p)) { - clean(prev, p); - } - } - } - - public E peek() { - for (;;) { - QNode h = traversalHead(); - QNode p = h.next; - if (p == null) { - return null; - } - Object x = p.get(); - if (p != x) { - if (!p.isData) { - return null; - } - if (x != null) { - return cast(x); - } - } - } - } - - @Override - public boolean isEmpty() { - for (;;) { - QNode h = traversalHead(); - QNode p = h.next; - if (p == null) { - return true; - } - Object x = p.get(); - if (p != x) { - if (!p.isData) { - return true; - } - if (x != null) { - return false; - } - } - } - } - - public boolean hasWaitingConsumer() { - for (;;) { - QNode h = traversalHead(); - QNode p = h.next; - if (p == null) { - return false; - } - Object x = p.get(); - if (p != x) { - return !p.isData; - } - } - } - - /** - * Returns the number of elements in this queue. If this queue contains more - * than Integer.MAX_VALUE elements, returns - * Integer.MAX_VALUE. - * - *

- * Beware that, unlike in most collections, this method is NOT a - * constant-time operation. Because of the asynchronous nature of these - * queues, determining the current number of elements requires an O(n) - * traversal. - * - * @return the number of elements in this queue - */ - @Override - public int size() { - int count = 0; - QNode h = traversalHead(); - for (QNode p = h.next; p != null && p.isData; p = p.next) { - Object x = p.get(); - if (x != null && x != p) { - if (++count == Integer.MAX_VALUE) { - break; - } - } - } - return count; - } - - public int getWaitingConsumerCount() { - int count = 0; - QNode h = traversalHead(); - for (QNode p = h.next; p != null && !p.isData; p = p.next) { - if (p.get() == null) { - if (++count == Integer.MAX_VALUE) { - break; - } - } - } - return count; - } - - public int remainingCapacity() { - return Integer.MAX_VALUE; - } -} +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2008 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU General Public License + * Version 2 only ("GPL") or the Common Development and Distribution License("CDDL") (collectively, + * the "License"). You may not use this file except in compliance with the License. You can obtain a + * copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html or + * glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific language governing + * permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each file and include the + * License file at glassfish/bootstrap/legal/LICENSE.txt. Sun designates this particular file as + * subject to the "Classpath" exception as provided by Sun in the GPL Version 2 section of the + * License file that accompanied this code. If applicable, add the following below the License + * Header, with the fields enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by only the CDDL or only the GPL Version 2, + * indicate your decision by adding "[Contributor] elects to include this software in this + * distribution under the [CDDL or GPL Version 2] license." If you don't indicate a single choice of + * license, a recipient has the option to distribute your version of this file under either the + * CDDL, the GPL Version 2 or to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such option by the copyright holder. + */ + +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 Expert Group and released to the + * public domain, as explained at http://creativecommons.org/licenses/publicdomain + */ + +package com.google.code.yanf4j.util; + +import java.util.AbstractQueue; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; +import java.util.concurrent.locks.LockSupport; + +/** + * An unbounded TransferQueue based on linked nodes. This queue orders elements FIFO + * (first-in-first-out) with respect to any given producer. The head of the queue is that + * element that has been on the queue the longest time for some producer. The tail of the + * queue is that element that has been on the queue the shortest time for some producer. + * + *

+ * Beware that, unlike in most collections, the size method is NOT a constant-time + * operation. Because of the asynchronous nature of these queues, determining the current number of + * elements requires a traversal of the elements. + * + *

+ * This class and its iterator implement all of the optional methods of the + * {@link Collection} and {@link Iterator} interfaces. + * + *

+ * Memory consistency effects: As with other concurrent collections, actions in a thread prior to + * placing an object into a {@code LinkedTransferQueue} + * happen-before actions subsequent to + * the access or removal of that element from the {@code LinkedTransferQueue} in another thread. + * + * @author Doug Lea + * @author The Netty Project (netty-dev@lists.jboss.org) + * @author Trustin Lee (tlee@redhat.com) + * + * @param the type of elements held in this collection + * + */ +public class LinkedTransferQueue extends AbstractQueue implements BlockingQueue { + + /* + * This class extends the approach used in FIFO-mode SynchronousQueues. See the internal + * documentation, as well as the PPoPP 2006 paper "Scalable Synchronous Queues" by Scherer, Lea & + * Scott (http://www.cs.rice.edu/~wns1/papers/2006-PPoPP-SQ.pdf) + * + * The main extension is to provide different Wait modes for the main "xfer" method that puts or + * takes items. These don't impact the basic dual-queue logic, but instead control whether or how + * threads block upon insertion of request or data nodes into the dual queue. It also uses + * slightly different conventions for tracking whether nodes are off-list or cancelled. + */ + + // Wait modes for xfer method + private static final int NOWAIT = 0; + private static final int TIMEOUT = 1; + private static final int WAIT = 2; + + /** The number of CPUs, for spin control */ + private static final int NCPUS = Runtime.getRuntime().availableProcessors(); + + /** + * The number of times to spin before blocking in timed waits. The value is empirically derived -- + * it works well across a variety of processors and OSes. Empirically, the best value seems not to + * vary with number of CPUs (beyond 2) so is just a constant. + */ + private static final int maxTimedSpins = NCPUS < 2 ? 0 : 32; + + /** + * The number of times to spin before blocking in untimed waits. This is greater than timed value + * because untimed waits spin faster since they don't need to check times on each spin. + */ + private static final int maxUntimedSpins = maxTimedSpins * 16; + + /** + * The number of nanoseconds for which it is faster to spin rather than to use timed park. A rough + * estimate suffices. + */ + private static final long spinForTimeoutThreshold = 1000L; + + /** + * Node class for LinkedTransferQueue. Opportunistically subclasses from AtomicReference to + * represent item. Uses Object, not E, to allow setting item to "this" after use, to avoid garbage + * retention. Similarly, setting the next field to this is used as sentinel that node is off list. + */ + private static final class QNode extends AtomicReference { + private static final long serialVersionUID = 5925596372370723938L; + + transient volatile QNode next; + transient volatile Thread waiter; // to control park/unpark + final boolean isData; + public long p1, p2, p3, p4, p5, p6, p7; + + QNode(Object item, boolean isData) { + super(item); + this.isData = isData; + } + + private static final AtomicReferenceFieldUpdater nextUpdater; + static { + AtomicReferenceFieldUpdater tmp = null; + try { + tmp = AtomicReferenceFieldUpdater.newUpdater(QNode.class, QNode.class, "next"); + + // Test if AtomicReferenceFieldUpdater is really working. + QNode testNode = new QNode(null, false); + tmp.set(testNode, testNode); + if (testNode.next != testNode) { + // Not set as expected - fall back to the safe mode. + throw new Exception(); + } + } catch (Throwable t) { + // Running in a restricted environment with a security manager. + tmp = null; + } + nextUpdater = tmp; + } + + boolean casNext(QNode cmp, QNode val) { + if (nextUpdater != null) { + return nextUpdater.compareAndSet(this, cmp, val); + } else { + return alternativeCasNext(cmp, val); + } + } + + private synchronized boolean alternativeCasNext(QNode cmp, QNode val) { + if (this.next == cmp) { + this.next = val; + return true; + } else { + return false; + } + } + } + + /** + * Padded version of AtomicReference used for head, tail and cleanMe, to alleviate contention + * across threads CASing one vs the other. + */ + public static final class PaddedAtomicReference extends AtomicReference { + private static final long serialVersionUID = 4684288940772921317L; + + // enough padding for 64bytes with 4byte refs + @SuppressWarnings("unused") + public Object p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, pe; + + public PaddedAtomicReference(T r) { + super(r); + } + } + + /** head of the queue */ + private final PaddedAtomicReference head; + /** tail of the queue */ + private final PaddedAtomicReference tail; + + /** + * Reference to a cancelled node that might not yet have been unlinked from queue because it was + * the last inserted node when it cancelled. + */ + private final PaddedAtomicReference cleanMe; + + /** + * Tries to cas nh as new head; if successful, unlink old head's next node to avoid garbage + * retention. + */ + private boolean advanceHead(QNode h, QNode nh) { + if (h == this.head.get() && this.head.compareAndSet(h, nh)) { + h.next = h; // forget old next + return true; + } + return false; + } + + /** + * Puts or takes an item. Used for most queue operations (except poll() and tryTransfer()). See + * the similar code in SynchronousQueue for detailed explanation. + * + * @param e the item or if null, signifies that this is a take + * @param mode the wait mode: NOWAIT, TIMEOUT, WAIT + * @param nanos timeout in nanosecs, used only if mode is TIMEOUT + * @return an item, or null on failure + */ + private Object xfer(Object e, int mode, long nanos) { + boolean isData = e != null; + QNode s = null; + final PaddedAtomicReference head = this.head; + final PaddedAtomicReference tail = this.tail; + + for (;;) { + QNode t = tail.get(); + QNode h = head.get(); + + if (t != null && (t == h || t.isData == isData)) { + if (s == null) { + s = new QNode(e, isData); + } + QNode last = t.next; + if (last != null) { + if (t == tail.get()) { + tail.compareAndSet(t, last); + } + } else if (t.casNext(null, s)) { + tail.compareAndSet(t, s); + return awaitFulfill(t, s, e, mode, nanos); + } + } + + else if (h != null) { + QNode first = h.next; + if (t == tail.get() && first != null && advanceHead(h, first)) { + Object x = first.get(); + if (x != first && first.compareAndSet(x, e)) { + LockSupport.unpark(first.waiter); + return isData ? e : x; + } + } + } + } + } + + /** + * Version of xfer for poll() and tryTransfer, which simplifies control paths both here and in + * xfer + */ + private Object fulfill(Object e) { + boolean isData = e != null; + final PaddedAtomicReference head = this.head; + final PaddedAtomicReference tail = this.tail; + + for (;;) { + QNode t = tail.get(); + QNode h = head.get(); + + if (t != null && (t == h || t.isData == isData)) { + QNode last = t.next; + if (t == tail.get()) { + if (last != null) { + tail.compareAndSet(t, last); + } else { + return null; + } + } + } else if (h != null) { + QNode first = h.next; + if (t == tail.get() && first != null && advanceHead(h, first)) { + Object x = first.get(); + if (x != first && first.compareAndSet(x, e)) { + LockSupport.unpark(first.waiter); + return isData ? e : x; + } + } + } + } + } + + /** + * Spins/blocks until node s is fulfilled or caller gives up, depending on wait mode. + * + * @param pred the predecessor of waiting node + * @param s the waiting node + * @param e the comparison value for checking match + * @param mode mode + * @param nanos timeout value + * @return matched item, or s if cancelled + */ + private Object awaitFulfill(QNode pred, QNode s, Object e, int mode, long nanos) { + if (mode == NOWAIT) { + return null; + } + + long lastTime = mode == TIMEOUT ? System.nanoTime() : 0; + Thread w = Thread.currentThread(); + int spins = -1; // set to desired spin count below + for (;;) { + if (w.isInterrupted()) { + s.compareAndSet(e, s); + } + Object x = s.get(); + if (x != e) { // Node was matched or cancelled + advanceHead(pred, s); // unlink if head + if (x == s) { // was cancelled + clean(pred, s); + return null; + } else if (x != null) { + s.set(s); // avoid garbage retention + return x; + } else { + return e; + } + } + if (mode == TIMEOUT) { + long now = System.nanoTime(); + nanos -= now - lastTime; + lastTime = now; + if (nanos <= 0) { + s.compareAndSet(e, s); // try to cancel + continue; + } + } + if (spins < 0) { + QNode h = this.head.get(); // only spin if at head + spins = h != null && h.next == s ? (mode == TIMEOUT ? maxTimedSpins : maxUntimedSpins) : 0; + } + if (spins > 0) { + --spins; + } else if (s.waiter == null) { + s.waiter = w; + } else if (mode != TIMEOUT) { + // LockSupport.park(this); + LockSupport.park(); // allows run on java5 + s.waiter = null; + spins = -1; + } else if (nanos > spinForTimeoutThreshold) { + // LockSupport.parkNanos(this, nanos); + LockSupport.parkNanos(nanos); + s.waiter = null; + spins = -1; + } + } + } + + /** + * Returns validated tail for use in cleaning methods + */ + private QNode getValidatedTail() { + for (;;) { + QNode h = this.head.get(); + QNode first = h.next; + if (first != null && first.next == first) { // help advance + advanceHead(h, first); + continue; + } + QNode t = this.tail.get(); + QNode last = t.next; + if (t == this.tail.get()) { + if (last != null) { + this.tail.compareAndSet(t, last); // help advance + } else { + return t; + } + } + } + } + + /** + * Gets rid of cancelled node s with original predecessor pred. + * + * @param pred predecessor of cancelled node + * @param s the cancelled node + */ + void clean(QNode pred, QNode s) { + Thread w = s.waiter; + if (w != null) { // Wake up thread + s.waiter = null; + if (w != Thread.currentThread()) { + LockSupport.unpark(w); + } + } + /* + * At any given time, exactly one node on list cannot be deleted -- the last inserted node. To + * accommodate this, if we cannot delete s, we save its predecessor as "cleanMe", processing the + * previously saved version first. At least one of node s or the node previously saved can + * always be processed, so this always terminates. + */ + while (pred.next == s) { + QNode oldpred = reclean(); // First, help get rid of cleanMe + QNode t = getValidatedTail(); + if (s != t) { // If not tail, try to unsplice + QNode sn = s.next; // s.next == s means s already off list + if (sn == s || pred.casNext(s, sn)) { + break; + } + } else if (oldpred == pred || // Already saved + oldpred == null && this.cleanMe.compareAndSet(null, pred)) { + break; // Postpone cleaning + } + } + } + + /** + * Tries to unsplice the cancelled node held in cleanMe that was previously uncleanable because it + * was at tail. + * + * @return current cleanMe node (or null) + */ + private QNode reclean() { + /* + * cleanMe is, or at one time was, predecessor of cancelled node s that was the tail so could + * not be unspliced. If s is no longer the tail, try to unsplice if necessary and make cleanMe + * slot available. This differs from similar code in clean() because we must check that pred + * still points to a cancelled node that must be unspliced -- if not, we can (must) clear + * cleanMe without unsplicing. This can loop only due to contention on casNext or clearing + * cleanMe. + */ + QNode pred; + while ((pred = this.cleanMe.get()) != null) { + QNode t = getValidatedTail(); + QNode s = pred.next; + if (s != t) { + QNode sn; + if (s == null || s == pred || s.get() != s || (sn = s.next) == s || pred.casNext(s, sn)) { + this.cleanMe.compareAndSet(pred, null); + } + } else { + break; + } + } + return pred; + } + + @SuppressWarnings("unchecked") + E cast(Object e) { + return (E) e; + } + + /** + * Creates an initially empty LinkedTransferQueue. + */ + public LinkedTransferQueue() { + QNode dummy = new QNode(null, false); + this.head = new PaddedAtomicReference(dummy); + this.tail = new PaddedAtomicReference(dummy); + this.cleanMe = new PaddedAtomicReference(null); + } + + /** + * Creates a LinkedTransferQueue initially containing the elements of the given + * collection, added in traversal order of the collection's iterator. + * + * @param c the collection of elements to initially contain + * @throws NullPointerException if the specified collection or any of its elements are null + */ + public LinkedTransferQueue(Collection c) { + this(); + addAll(c); + } + + public void put(E e) throws InterruptedException { + if (e == null) { + throw new NullPointerException(); + } + if (Thread.interrupted()) { + throw new InterruptedException(); + } + xfer(e, NOWAIT, 0); + } + + public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException { + if (e == null) { + throw new NullPointerException(); + } + if (Thread.interrupted()) { + throw new InterruptedException(); + } + xfer(e, NOWAIT, 0); + return true; + } + + public boolean offer(E e) { + if (e == null) { + throw new NullPointerException(); + } + xfer(e, NOWAIT, 0); + return true; + } + + public void transfer(E e) throws InterruptedException { + if (e == null) { + throw new NullPointerException(); + } + if (xfer(e, WAIT, 0) == null) { + Thread.interrupted(); + throw new InterruptedException(); + } + } + + public boolean tryTransfer(E e, long timeout, TimeUnit unit) throws InterruptedException { + if (e == null) { + throw new NullPointerException(); + } + if (xfer(e, TIMEOUT, unit.toNanos(timeout)) != null) { + return true; + } + if (!Thread.interrupted()) { + return false; + } + throw new InterruptedException(); + } + + public boolean tryTransfer(E e) { + if (e == null) { + throw new NullPointerException(); + } + return fulfill(e) != null; + } + + public E take() throws InterruptedException { + Object e = xfer(null, WAIT, 0); + if (e != null) { + return cast(e); + } + Thread.interrupted(); + throw new InterruptedException(); + } + + public E poll(long timeout, TimeUnit unit) throws InterruptedException { + Object e = xfer(null, TIMEOUT, unit.toNanos(timeout)); + if (e != null || !Thread.interrupted()) { + return cast(e); + } + throw new InterruptedException(); + } + + public E poll() { + return cast(fulfill(null)); + } + + public int drainTo(Collection c) { + if (c == null) { + throw new NullPointerException(); + } + if (c == this) { + throw new IllegalArgumentException(); + } + int n = 0; + E e; + while ((e = poll()) != null) { + c.add(e); + ++n; + } + return n; + } + + public int drainTo(Collection c, int maxElements) { + if (c == null) { + throw new NullPointerException(); + } + if (c == this) { + throw new IllegalArgumentException(); + } + int n = 0; + E e; + while (n < maxElements && (e = poll()) != null) { + c.add(e); + ++n; + } + return n; + } + + // Traversal-based methods + + /** + * Return head after performing any outstanding helping steps + */ + QNode traversalHead() { + for (;;) { + QNode t = this.tail.get(); + QNode h = this.head.get(); + if (h != null && t != null) { + QNode last = t.next; + QNode first = h.next; + if (t == this.tail.get()) { + if (last != null) { + this.tail.compareAndSet(t, last); + } else if (first != null) { + Object x = first.get(); + if (x == first) { + advanceHead(h, first); + } else { + return h; + } + } else { + return h; + } + } + } + } + } + + @Override + public Iterator iterator() { + return new Itr(); + } + + /** + * Iterators. Basic strategy is to traverse list, treating non-data (i.e., request) nodes as + * terminating list. Once a valid data node is found, the item is cached so that the next call to + * next() will return it even if subsequently removed. + */ + class Itr implements Iterator { + QNode nextNode; // Next node to return next + QNode currentNode; // last returned node, for remove() + QNode prevNode; // predecessor of last returned node + E nextItem; // Cache of next item, once commited to in next + + Itr() { + this.nextNode = traversalHead(); + advance(); + } + + E advance() { + this.prevNode = this.currentNode; + this.currentNode = this.nextNode; + E x = this.nextItem; + + QNode p = this.nextNode.next; + for (;;) { + if (p == null || !p.isData) { + this.nextNode = null; + this.nextItem = null; + return x; + } + Object item = p.get(); + if (item != p && item != null) { + this.nextNode = p; + this.nextItem = cast(item); + return x; + } + this.prevNode = p; + p = p.next; + } + } + + public boolean hasNext() { + return this.nextNode != null; + } + + public E next() { + if (this.nextNode == null) { + throw new NoSuchElementException(); + } + return advance(); + } + + public void remove() { + QNode p = this.currentNode; + QNode prev = this.prevNode; + if (prev == null || p == null) { + throw new IllegalStateException(); + } + Object x = p.get(); + if (x != null && x != p && p.compareAndSet(x, p)) { + clean(prev, p); + } + } + } + + public E peek() { + for (;;) { + QNode h = traversalHead(); + QNode p = h.next; + if (p == null) { + return null; + } + Object x = p.get(); + if (p != x) { + if (!p.isData) { + return null; + } + if (x != null) { + return cast(x); + } + } + } + } + + @Override + public boolean isEmpty() { + for (;;) { + QNode h = traversalHead(); + QNode p = h.next; + if (p == null) { + return true; + } + Object x = p.get(); + if (p != x) { + if (!p.isData) { + return true; + } + if (x != null) { + return false; + } + } + } + } + + public boolean hasWaitingConsumer() { + for (;;) { + QNode h = traversalHead(); + QNode p = h.next; + if (p == null) { + return false; + } + Object x = p.get(); + if (p != x) { + return !p.isData; + } + } + } + + /** + * Returns the number of elements in this queue. If this queue contains more than + * Integer.MAX_VALUE elements, returns Integer.MAX_VALUE. + * + *

+ * Beware that, unlike in most collections, this method is NOT a constant-time operation. + * Because of the asynchronous nature of these queues, determining the current number of elements + * requires an O(n) traversal. + * + * @return the number of elements in this queue + */ + @Override + public int size() { + int count = 0; + QNode h = traversalHead(); + for (QNode p = h.next; p != null && p.isData; p = p.next) { + Object x = p.get(); + if (x != null && x != p) { + if (++count == Integer.MAX_VALUE) { + break; + } + } + } + return count; + } + + public int getWaitingConsumerCount() { + int count = 0; + QNode h = traversalHead(); + for (QNode p = h.next; p != null && !p.isData; p = p.next) { + if (p.get() == null) { + if (++count == Integer.MAX_VALUE) { + break; + } + } + } + return count; + } + + public int remainingCapacity() { + return Integer.MAX_VALUE; + } +} diff --git a/src/main/java/com/google/code/yanf4j/util/MapBackedSet.java b/src/main/java/com/google/code/yanf4j/util/MapBackedSet.java index 29084bcd5..899b14dd2 100644 --- a/src/main/java/com/google/code/yanf4j/util/MapBackedSet.java +++ b/src/main/java/com/google/code/yanf4j/util/MapBackedSet.java @@ -9,53 +9,52 @@ /** * A {@link Map}-backed {@link Set}. - * + * * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev: 597692 $, $Date: 2007-11-23 08:56:32 -0700 (Fri, 23 Nov 2007) - * $ + * @version $Rev: 597692 $, $Date: 2007-11-23 08:56:32 -0700 (Fri, 23 Nov 2007) $ */ public class MapBackedSet extends AbstractSet implements Serializable { - private static final long serialVersionUID = -8347878570391674042L; + private static final long serialVersionUID = -8347878570391674042L; - protected final Map map; + protected final Map map; - public MapBackedSet(Map map) { - this.map = map; - } + public MapBackedSet(Map map) { + this.map = map; + } - public MapBackedSet(Map map, Collection c) { - this.map = map; - addAll(c); - } + public MapBackedSet(Map map, Collection c) { + this.map = map; + addAll(c); + } - @Override - public int size() { - return map.size(); - } + @Override + public int size() { + return map.size(); + } - @Override - public boolean contains(Object o) { - return map.containsKey(o); - } + @Override + public boolean contains(Object o) { + return map.containsKey(o); + } - @Override - public Iterator iterator() { - return map.keySet().iterator(); - } + @Override + public Iterator iterator() { + return map.keySet().iterator(); + } - @Override - public boolean add(E o) { - return map.put(o, Boolean.TRUE) == null; - } + @Override + public boolean add(E o) { + return map.put(o, Boolean.TRUE) == null; + } - @Override - public boolean remove(Object o) { - return map.remove(o) != null; - } + @Override + public boolean remove(Object o) { + return map.remove(o) != null; + } - @Override - public void clear() { - map.clear(); - } + @Override + public void clear() { + map.clear(); + } } diff --git a/src/main/java/com/google/code/yanf4j/util/PropertyUtils.java b/src/main/java/com/google/code/yanf4j/util/PropertyUtils.java index 95f80c869..d40bdd739 100644 --- a/src/main/java/com/google/code/yanf4j/util/PropertyUtils.java +++ b/src/main/java/com/google/code/yanf4j/util/PropertyUtils.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.util; @@ -32,27 +26,27 @@ */ public class PropertyUtils { - public static int getPropertyAsInteger(Properties props, String propName) { - return Integer.parseInt(PropertyUtils.getProperty(props, propName)); - } + public static int getPropertyAsInteger(Properties props, String propName) { + return Integer.parseInt(PropertyUtils.getProperty(props, propName)); + } - public static String getProperty(Properties props, String name) { - return props.getProperty(name).trim(); - } + public static String getProperty(Properties props, String name) { + return props.getProperty(name).trim(); + } - public static boolean getPropertyAsBoolean(Properties props, String name) { - return Boolean.valueOf(getProperty(props, name)); - } + public static boolean getPropertyAsBoolean(Properties props, String name) { + return Boolean.valueOf(getProperty(props, name)); + } - public static long getPropertyAsLong(Properties props, String name) { - return Long.parseLong(getProperty(props, name)); - } + public static long getPropertyAsLong(Properties props, String name) { + return Long.parseLong(getProperty(props, name)); + } - public static short getPropertyAsShort(Properties props, String name) { - return Short.parseShort(getProperty(props, name)); - } + public static short getPropertyAsShort(Properties props, String name) { + return Short.parseShort(getProperty(props, name)); + } - public static byte getPropertyAsByte(Properties props, String name) { - return Byte.parseByte(getProperty(props, name)); - } + public static byte getPropertyAsByte(Properties props, String name) { + return Byte.parseByte(getProperty(props, name)); + } } diff --git a/src/main/java/com/google/code/yanf4j/util/ResourcesUtils.java b/src/main/java/com/google/code/yanf4j/util/ResourcesUtils.java index b568660bf..e5652d237 100644 --- a/src/main/java/com/google/code/yanf4j/util/ResourcesUtils.java +++ b/src/main/java/com/google/code/yanf4j/util/ResourcesUtils.java @@ -1,13 +1,10 @@ /** - *Copyright [2008] [dennis zhuang] - *Licensed 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 + * Copyright [2008] [dennis zhuang] Licensed 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 com.google.code.yanf4j.util; @@ -27,216 +24,185 @@ */ public class ResourcesUtils extends Object { - /** */ - /** - * Returns the URL of the resource on the classpath - * - * @param resource - * The resource to find - * @throws IOException - * If the resource cannot be found or read - * @return The resource - */ - public static URL getResourceURL(String resource) throws IOException { - URL url = null; - ClassLoader loader = ResourcesUtils.class.getClassLoader(); - if (loader != null) { - url = loader.getResource(resource); - } - if (url == null) { - url = ClassLoader.getSystemResource(resource); - } - if (url == null) { - throw new IOException("Could not find resource " + resource); - } - return url; - } + /** */ + /** + * Returns the URL of the resource on the classpath + * + * @param resource The resource to find + * @throws IOException If the resource cannot be found or read + * @return The resource + */ + public static URL getResourceURL(String resource) throws IOException { + URL url = null; + ClassLoader loader = ResourcesUtils.class.getClassLoader(); + if (loader != null) { + url = loader.getResource(resource); + } + if (url == null) { + url = ClassLoader.getSystemResource(resource); + } + if (url == null) { + throw new IOException("Could not find resource " + resource); + } + return url; + } - /** */ - /** - * Returns the URL of the resource on the classpath - * - * @param loader - * The classloader used to load the resource - * @param resource - * The resource to find - * @throws IOException - * If the resource cannot be found or read - * @return The resource - */ - public static URL getResourceURL(ClassLoader loader, String resource) - throws IOException { - URL url = null; - if (loader != null) { - url = loader.getResource(resource); - } - if (url == null) { - url = ClassLoader.getSystemResource(resource); - } - if (url == null) { - throw new IOException("Could not find resource " + resource); - } - return url; - } + /** */ + /** + * Returns the URL of the resource on the classpath + * + * @param loader The classloader used to load the resource + * @param resource The resource to find + * @throws IOException If the resource cannot be found or read + * @return The resource + */ + public static URL getResourceURL(ClassLoader loader, String resource) throws IOException { + URL url = null; + if (loader != null) { + url = loader.getResource(resource); + } + if (url == null) { + url = ClassLoader.getSystemResource(resource); + } + if (url == null) { + throw new IOException("Could not find resource " + resource); + } + return url; + } - /** */ - /** - * Returns a resource on the classpath as a Stream object - * - * @param resource - * The resource to find - * @throws IOException - * If the resource cannot be found or read - * @return The resource - */ - public static InputStream getResourceAsStream(String resource) - throws IOException { - InputStream in = null; - ClassLoader loader = ResourcesUtils.class.getClassLoader(); - if (loader != null) { - in = loader.getResourceAsStream(resource); - } - if (in == null) { - in = ClassLoader.getSystemResourceAsStream(resource); - } - if (in == null) { - throw new IOException("Could not find resource " + resource); - } - return in; - } + /** */ + /** + * Returns a resource on the classpath as a Stream object + * + * @param resource The resource to find + * @throws IOException If the resource cannot be found or read + * @return The resource + */ + public static InputStream getResourceAsStream(String resource) throws IOException { + InputStream in = null; + ClassLoader loader = ResourcesUtils.class.getClassLoader(); + if (loader != null) { + in = loader.getResourceAsStream(resource); + } + if (in == null) { + in = ClassLoader.getSystemResourceAsStream(resource); + } + if (in == null) { + throw new IOException("Could not find resource " + resource); + } + return in; + } - /** */ - /** - * Returns a resource on the classpath as a Stream object - * - * @param loader - * The classloader used to load the resource - * @param resource - * The resource to find - * @throws IOException - * If the resource cannot be found or read - * @return The resource - */ - public static InputStream getResourceAsStream(ClassLoader loader, - String resource) throws IOException { - InputStream in = null; - if (loader != null) { - in = loader.getResourceAsStream(resource); - } - if (in == null) { - in = ClassLoader.getSystemResourceAsStream(resource); - } - if (in == null) { - throw new IOException("Could not find resource " + resource); - } - return in; - } + /** */ + /** + * Returns a resource on the classpath as a Stream object + * + * @param loader The classloader used to load the resource + * @param resource The resource to find + * @throws IOException If the resource cannot be found or read + * @return The resource + */ + public static InputStream getResourceAsStream(ClassLoader loader, String resource) + throws IOException { + InputStream in = null; + if (loader != null) { + in = loader.getResourceAsStream(resource); + } + if (in == null) { + in = ClassLoader.getSystemResourceAsStream(resource); + } + if (in == null) { + throw new IOException("Could not find resource " + resource); + } + return in; + } - /** */ - /** - * Returns a resource on the classpath as a Properties object - * - * @param resource - * The resource to find - * @throws IOException - * If the resource cannot be found or read - * @return The resource - */ - public static Properties getResourceAsProperties(String resource) - throws IOException { - Properties props = new Properties(); - InputStream in = null; - String propfile = resource; - in = getResourceAsStream(propfile); - props.load(in); - in.close(); - return props; - } + /** */ + /** + * Returns a resource on the classpath as a Properties object + * + * @param resource The resource to find + * @throws IOException If the resource cannot be found or read + * @return The resource + */ + public static Properties getResourceAsProperties(String resource) throws IOException { + Properties props = new Properties(); + InputStream in = null; + String propfile = resource; + in = getResourceAsStream(propfile); + props.load(in); + in.close(); + return props; + } - /** */ - /** - * Returns a resource on the classpath as a Properties object - * - * @param loader - * The classloader used to load the resource - * @param resource - * The resource to find - * @throws IOException - * If the resource cannot be found or read - * @return The resource - */ - public static Properties getResourceAsProperties(ClassLoader loader, - String resource) throws IOException { - Properties props = new Properties(); - InputStream in = null; - String propfile = resource; - in = getResourceAsStream(loader, propfile); - props.load(in); - in.close(); - return props; - } + /** */ + /** + * Returns a resource on the classpath as a Properties object + * + * @param loader The classloader used to load the resource + * @param resource The resource to find + * @throws IOException If the resource cannot be found or read + * @return The resource + */ + public static Properties getResourceAsProperties(ClassLoader loader, String resource) + throws IOException { + Properties props = new Properties(); + InputStream in = null; + String propfile = resource; + in = getResourceAsStream(loader, propfile); + props.load(in); + in.close(); + return props; + } - /** */ - /** - * Returns a resource on the classpath as a Reader object - * - * @param resource - * The resource to find - * @throws IOException - * If the resource cannot be found or read - * @return The resource - */ - public static InputStreamReader getResourceAsReader(String resource) - throws IOException { - return new InputStreamReader(getResourceAsStream(resource)); - } + /** */ + /** + * Returns a resource on the classpath as a Reader object + * + * @param resource The resource to find + * @throws IOException If the resource cannot be found or read + * @return The resource + */ + public static InputStreamReader getResourceAsReader(String resource) throws IOException { + return new InputStreamReader(getResourceAsStream(resource)); + } - /** */ - /** - * Returns a resource on the classpath as a Reader object - * - * @param loader - * The classloader used to load the resource - * @param resource - * The resource to find - * @throws IOException - * If the resource cannot be found or read - * @return The resource - */ - public static Reader getResourceAsReader(ClassLoader loader, - String resource) throws IOException { - return new InputStreamReader(getResourceAsStream(loader, resource)); - } + /** */ + /** + * Returns a resource on the classpath as a Reader object + * + * @param loader The classloader used to load the resource + * @param resource The resource to find + * @throws IOException If the resource cannot be found or read + * @return The resource + */ + public static Reader getResourceAsReader(ClassLoader loader, String resource) throws IOException { + return new InputStreamReader(getResourceAsStream(loader, resource)); + } - /** */ - /** - * Returns a resource on the classpath as a File object - * - * @param resource - * The resource to find - * @throws IOException - * If the resource cannot be found or read - * @return The resource - */ - public static File getResourceAsFile(String resource) throws IOException { - return new File(getResourceURL(resource).getFile()); - } + /** */ + /** + * Returns a resource on the classpath as a File object + * + * @param resource The resource to find + * @throws IOException If the resource cannot be found or read + * @return The resource + */ + public static File getResourceAsFile(String resource) throws IOException { + return new File(getResourceURL(resource).getFile()); + } - /** */ - /** - * Returns a resource on the classpath as a File object - * - * @param loader - * The classloader used to load the resource - * @param resource - * The resource to find - * @throws IOException - * If the resource cannot be found or read - * @return The resource - */ - public static File getResourceAsFile(ClassLoader loader, String resource) - throws IOException { - return new File(getResourceURL(loader, resource).getFile()); - } + /** */ + /** + * Returns a resource on the classpath as a File object + * + * @param loader The classloader used to load the resource + * @param resource The resource to find + * @throws IOException If the resource cannot be found or read + * @return The resource + */ + public static File getResourceAsFile(ClassLoader loader, String resource) throws IOException { + return new File(getResourceURL(loader, resource).getFile()); + } -} \ No newline at end of file +} diff --git a/src/main/java/com/google/code/yanf4j/util/SelectorFactory.java b/src/main/java/com/google/code/yanf4j/util/SelectorFactory.java index 86db4be8e..4ae768996 100644 --- a/src/main/java/com/google/code/yanf4j/util/SelectorFactory.java +++ b/src/main/java/com/google/code/yanf4j/util/SelectorFactory.java @@ -1,169 +1,158 @@ -/* - * The contents of this file are subject to the terms - * of the Common Development and Distribution License - * (the License). You may not use this file except in - * compliance with the License. - * - * You can obtain a copy of the license at - * https://glassfish.dev.java.net/public/CDDLv1.0.html or - * glassfish/bootstrap/legal/CDDLv1.0.txt. - * See the License for the specific language governing - * permissions and limitations under the License. - * - * When distributing Covered Code, include this CDDL - * Header Notice in each file and include the License file - * at glassfish/bootstrap/legal/CDDLv1.0.txt. - * If applicable, add the following below the CDDL Header, - * with the fields enclosed by brackets [] replaced by - * you own identifying information: - * "Portions Copyrighted [year] [name of copyright owner]" - * - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. - */ -package com.google.code.yanf4j.util; - -import java.io.IOException; -import java.nio.channels.Selector; -import java.util.EmptyStackException; -import java.util.Stack; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Temp selector factory,come from grizzly - * - * @author dennis zhuang - */ -public class SelectorFactory { - - public static final int DEFAULT_MAX_SELECTORS = 20; - - private static final Logger logger = LoggerFactory - .getLogger(SelectorFactory.class); - /** - * The timeout before we exit. - */ - public final static long timeout = 5000; - - /** - * The number of Selector to create. - */ - private static int maxSelectors; - - /** - * Cache of Selector - */ - private final static Stack selectors = new Stack(); - - /** - * Creates the Selector - */ - static { - try { - setMaxSelectors(DEFAULT_MAX_SELECTORS); - } catch (IOException ex) { - logger.warn("SelectorFactory initializing Selector pool", ex); - } - } - - /** - * Set max selector pool size. - * - * @param size - * max pool size - */ - public final static void setMaxSelectors(int size) throws IOException { - synchronized (selectors) { - if (size < maxSelectors) { - reduce(size); - } else if (size > maxSelectors) { - grow(size); - } - - maxSelectors = size; - } - } - - /** - * Returns max selector pool size - * - * @return max pool size - */ - public final static int getMaxSelectors() { - return maxSelectors; - } - - /** - * Get a exclusive Selector - * - * @return Selector - */ - public final static Selector getSelector() { - synchronized (selectors) { - Selector s = null; - try { - if (selectors.size() != 0) { - s = selectors.pop(); - } - } catch (EmptyStackException ex) { - } - - int attempts = 0; - try { - while (s == null && attempts < 2) { - selectors.wait(timeout); - try { - if (selectors.size() != 0) { - s = selectors.pop(); - } - } catch (EmptyStackException ex) { - break; - } - attempts++; - } - } catch (InterruptedException ex) { - } - return s; - } - } - - /** - * Return the Selector to the cache - * - * @param s - * Selector - */ - public final static void returnSelector(Selector s) { - synchronized (selectors) { - selectors.push(s); - if (selectors.size() == 1) { - selectors.notify(); - } - } - } - - /** - * Increase Selector pool size - */ - private static void grow(int size) throws IOException { - for (int i = 0; i < size - maxSelectors; i++) { - selectors.add(Selector.open()); - } - } - - /** - * Decrease Selector pool size - */ - private static void reduce(int size) { - for (int i = 0; i < maxSelectors - size; i++) { - try { - Selector selector = selectors.pop(); - selector.close(); - } catch (IOException e) { - logger.error("SelectorFactory.reduce", e); - } - } - } - -} +/* + * The contents of this file are subject to the terms of the Common Development and Distribution + * License (the License). You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at https://glassfish.dev.java.net/public/CDDLv1.0.html or + * glassfish/bootstrap/legal/CDDLv1.0.txt. See the License for the specific language governing + * permissions and limitations under the License. + * + * When distributing Covered Code, include this CDDL Header Notice in each file and include the + * License file at glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable, add the following below + * the CDDL Header, with the fields enclosed by brackets [] replaced by you own identifying + * information: "Portions Copyrighted [year] [name of copyright owner]" + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + */ +package com.google.code.yanf4j.util; + +import java.io.IOException; +import java.nio.channels.Selector; +import java.util.EmptyStackException; +import java.util.Stack; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Temp selector factory,come from grizzly + * + * @author dennis zhuang + */ +public class SelectorFactory { + + public static final int DEFAULT_MAX_SELECTORS = 20; + + private static final Logger logger = LoggerFactory.getLogger(SelectorFactory.class); + /** + * The timeout before we exit. + */ + public final static long timeout = 5000; + + /** + * The number of Selector to create. + */ + private static int maxSelectors; + + /** + * Cache of Selector + */ + private final static Stack selectors = new Stack(); + + /** + * Creates the Selector + */ + static { + try { + setMaxSelectors(DEFAULT_MAX_SELECTORS); + } catch (IOException ex) { + logger.warn("SelectorFactory initializing Selector pool", ex); + } + } + + /** + * Set max selector pool size. + * + * @param size max pool size + */ + public final static void setMaxSelectors(int size) throws IOException { + synchronized (selectors) { + if (size < maxSelectors) { + reduce(size); + } else if (size > maxSelectors) { + grow(size); + } + + maxSelectors = size; + } + } + + /** + * Returns max selector pool size + * + * @return max pool size + */ + public final static int getMaxSelectors() { + return maxSelectors; + } + + /** + * Get a exclusive Selector + * + * @return Selector + */ + public final static Selector getSelector() { + synchronized (selectors) { + Selector s = null; + try { + if (selectors.size() != 0) { + s = selectors.pop(); + } + } catch (EmptyStackException ex) { + } + + int attempts = 0; + try { + while (s == null && attempts < 2) { + selectors.wait(timeout); + try { + if (selectors.size() != 0) { + s = selectors.pop(); + } + } catch (EmptyStackException ex) { + break; + } + attempts++; + } + } catch (InterruptedException ex) { + } + return s; + } + } + + /** + * Return the Selector to the cache + * + * @param s Selector + */ + public final static void returnSelector(Selector s) { + synchronized (selectors) { + selectors.push(s); + if (selectors.size() == 1) { + selectors.notify(); + } + } + } + + /** + * Increase Selector pool size + */ + private static void grow(int size) throws IOException { + for (int i = 0; i < size - maxSelectors; i++) { + selectors.add(Selector.open()); + } + } + + /** + * Decrease Selector pool size + */ + private static void reduce(int size) { + for (int i = 0; i < maxSelectors - size; i++) { + try { + Selector selector = selectors.pop(); + selector.close(); + } catch (IOException e) { + logger.error("SelectorFactory.reduce", e); + } + } + } + +} diff --git a/src/main/java/com/google/code/yanf4j/util/ShiftAndByteBufferMatcher.java b/src/main/java/com/google/code/yanf4j/util/ShiftAndByteBufferMatcher.java index a792f7d59..8e5cc517a 100644 --- a/src/main/java/com/google/code/yanf4j/util/ShiftAndByteBufferMatcher.java +++ b/src/main/java/com/google/code/yanf4j/util/ShiftAndByteBufferMatcher.java @@ -1,30 +1,23 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.util; import java.util.ArrayList; import java.util.List; - import com.google.code.yanf4j.buffer.IoBuffer; /** @@ -35,67 +28,67 @@ */ public class ShiftAndByteBufferMatcher implements ByteBufferMatcher { - private int[] b; - private int mask; + private int[] b; + private int mask; - private int patternLimit; - private int patternPos; - private int patternLen; + private int patternLimit; + private int patternPos; + private int patternLen; - public ShiftAndByteBufferMatcher(IoBuffer pat) { - if (pat == null || pat.remaining() == 0) { - throw new IllegalArgumentException("blank buffer"); - } - this.patternLimit = pat.limit(); - this.patternPos = pat.position(); - this.patternLen = pat.remaining(); - preprocess(pat); - this.mask = 1 << (this.patternLen - 1); - } + public ShiftAndByteBufferMatcher(IoBuffer pat) { + if (pat == null || pat.remaining() == 0) { + throw new IllegalArgumentException("blank buffer"); + } + this.patternLimit = pat.limit(); + this.patternPos = pat.position(); + this.patternLen = pat.remaining(); + preprocess(pat); + this.mask = 1 << (this.patternLen - 1); + } - /** - * Ԥ���� - * - * @param pat - */ - private void preprocess(IoBuffer pat) { - this.b = new int[256]; - for (int i = this.patternPos; i < this.patternLimit; i++) { - int p = ByteBufferUtils.uByte(pat.get(i)); - this.b[p] = this.b[p] | (1 << i); - } - } + /** + * Ԥ���� + * + * @param pat + */ + private void preprocess(IoBuffer pat) { + this.b = new int[256]; + for (int i = this.patternPos; i < this.patternLimit; i++) { + int p = ByteBufferUtils.uByte(pat.get(i)); + this.b[p] = this.b[p] | (1 << i); + } + } - public final List matchAll(IoBuffer buffer) { - List matches = new ArrayList(); - int bufferLimit = buffer.limit(); - int d = 0; - for (int pos = buffer.position(); pos < bufferLimit; pos++) { - d <<= 1; - d |= 1; - d &= this.b[ByteBufferUtils.uByte(buffer.get(pos))]; - if ((d & this.mask) != 0) { - matches.add(pos - this.patternLen + 1); - } - } - return matches; - } + public final List matchAll(IoBuffer buffer) { + List matches = new ArrayList(); + int bufferLimit = buffer.limit(); + int d = 0; + for (int pos = buffer.position(); pos < bufferLimit; pos++) { + d <<= 1; + d |= 1; + d &= this.b[ByteBufferUtils.uByte(buffer.get(pos))]; + if ((d & this.mask) != 0) { + matches.add(pos - this.patternLen + 1); + } + } + return matches; + } - public final int matchFirst(IoBuffer buffer) { - if (buffer == null) { - return -1; - } - int bufferLimit = buffer.limit(); - int d = 0; - for (int pos = buffer.position(); pos < bufferLimit; pos++) { - d <<= 1; - d |= 1; - d &= this.b[buffer.get(pos) & 0XFF]; - if ((d & this.mask) != 0) { - return pos - this.patternLen + 1; - } - } - return -1; - } + public final int matchFirst(IoBuffer buffer) { + if (buffer == null) { + return -1; + } + int bufferLimit = buffer.limit(); + int d = 0; + for (int pos = buffer.position(); pos < bufferLimit; pos++) { + d <<= 1; + d |= 1; + d &= this.b[buffer.get(pos) & 0XFF]; + if ((d & this.mask) != 0) { + return pos - this.patternLen + 1; + } + } + return -1; + } } diff --git a/src/main/java/com/google/code/yanf4j/util/ShiftOrByteBufferMatcher.java b/src/main/java/com/google/code/yanf4j/util/ShiftOrByteBufferMatcher.java index e4bc2d3db..4f719fbe3 100644 --- a/src/main/java/com/google/code/yanf4j/util/ShiftOrByteBufferMatcher.java +++ b/src/main/java/com/google/code/yanf4j/util/ShiftOrByteBufferMatcher.java @@ -1,30 +1,23 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.util; import java.util.ArrayList; import java.util.List; - import com.google.code.yanf4j.buffer.IoBuffer; /** @@ -35,67 +28,66 @@ */ public class ShiftOrByteBufferMatcher implements ByteBufferMatcher { - private int[] b; - private int lim; + private int[] b; + private int lim; - private int patternLen; + private int patternLen; - public ShiftOrByteBufferMatcher(IoBuffer pat) { - if (pat == null || pat.remaining() == 0) { - throw new IllegalArgumentException("blank buffer"); - } - this.patternLen = pat.remaining(); - preprocess(pat); - } + public ShiftOrByteBufferMatcher(IoBuffer pat) { + if (pat == null || pat.remaining() == 0) { + throw new IllegalArgumentException("blank buffer"); + } + this.patternLen = pat.remaining(); + preprocess(pat); + } - /** - * Ԥ���� - * - * @param pat - */ - private void preprocess(IoBuffer pat) { - this.b = new int[256]; - this.lim = 0; - for (int i = 0; i < 256; i++) { - this.b[i] = ~0; + /** + * Ԥ���� + * + * @param pat + */ + private void preprocess(IoBuffer pat) { + this.b = new int[256]; + this.lim = 0; + for (int i = 0; i < 256; i++) { + this.b[i] = ~0; - } - for (int i = 0, j = 1; i < this.patternLen; i++, j <<= 1) { - this.b[ByteBufferUtils.uByte(pat.get(i))] &= ~j; - this.lim |= j; - } - this.lim = ~(this.lim >> 1); + } + for (int i = 0, j = 1; i < this.patternLen; i++, j <<= 1) { + this.b[ByteBufferUtils.uByte(pat.get(i))] &= ~j; + this.lim |= j; + } + this.lim = ~(this.lim >> 1); - } + } - public final List matchAll(IoBuffer buffer) { - List matches = new ArrayList(); - int bufferLimit = buffer.limit(); - int state = ~0; - for (int pos = buffer.position(); pos < bufferLimit; pos++) { - state <<= 1; - state |= this.b[ByteBufferUtils.uByte(buffer.get(pos))]; - if (state < this.lim) { - matches.add(pos - this.patternLen + 1); - } - } - return matches; - } + public final List matchAll(IoBuffer buffer) { + List matches = new ArrayList(); + int bufferLimit = buffer.limit(); + int state = ~0; + for (int pos = buffer.position(); pos < bufferLimit; pos++) { + state <<= 1; + state |= this.b[ByteBufferUtils.uByte(buffer.get(pos))]; + if (state < this.lim) { + matches.add(pos - this.patternLen + 1); + } + } + return matches; + } - public final int matchFirst(IoBuffer buffer) { - if (buffer == null) { - return -1; - } - int bufferLimit = buffer.limit(); - int state = ~0; - for (int pos = buffer.position(); pos < bufferLimit; pos++) { - state = (state <<= 1) - | this.b[ByteBufferUtils.uByte(buffer.get(pos))]; - if (state < this.lim) { - return pos - this.patternLen + 1; - } - } - return -1; - } + public final int matchFirst(IoBuffer buffer) { + if (buffer == null) { + return -1; + } + int bufferLimit = buffer.limit(); + int state = ~0; + for (int pos = buffer.position(); pos < bufferLimit; pos++) { + state = (state <<= 1) | this.b[ByteBufferUtils.uByte(buffer.get(pos))]; + if (state < this.lim) { + return pos - this.patternLen + 1; + } + } + return -1; + } } diff --git a/src/main/java/com/google/code/yanf4j/util/SimpleQueue.java b/src/main/java/com/google/code/yanf4j/util/SimpleQueue.java index f91ca8b08..bf66fa00b 100644 --- a/src/main/java/com/google/code/yanf4j/util/SimpleQueue.java +++ b/src/main/java/com/google/code/yanf4j/util/SimpleQueue.java @@ -10,36 +10,36 @@ */ public class SimpleQueue extends java.util.AbstractQueue { - protected final LinkedList list; + protected final LinkedList list; - public SimpleQueue(int initializeCapacity) { - this.list = new LinkedList(); - } + public SimpleQueue(int initializeCapacity) { + this.list = new LinkedList(); + } - public SimpleQueue() { - this(100); - } + public SimpleQueue() { + this(100); + } - public synchronized boolean offer(T e) { - return this.list.add(e); - } + public synchronized boolean offer(T e) { + return this.list.add(e); + } - public synchronized T peek() { - return this.list.peek(); - } + public synchronized T peek() { + return this.list.peek(); + } - public synchronized T poll() { - return this.list.poll(); - } + public synchronized T poll() { + return this.list.poll(); + } - @Override - public Iterator iterator() { - return this.list.iterator(); - } + @Override + public Iterator iterator() { + return this.list.iterator(); + } - @Override - public int size() { - return this.list.size(); - } + @Override + public int size() { + return this.list.size(); + } } diff --git a/src/main/java/com/google/code/yanf4j/util/SystemUtils.java b/src/main/java/com/google/code/yanf4j/util/SystemUtils.java index cca0ea643..b3844b729 100644 --- a/src/main/java/com/google/code/yanf4j/util/SystemUtils.java +++ b/src/main/java/com/google/code/yanf4j/util/SystemUtils.java @@ -1,164 +1,149 @@ -/** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 - */ -/** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 com.google.code.yanf4j.util; - -import java.io.IOException; -import java.lang.reflect.Method; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.nio.channels.Selector; -import java.nio.channels.spi.SelectorProvider; -import java.util.Queue; -import java.util.Random; - -/** - * System utils - * - * @author dennis - * - */ -public final class SystemUtils { - - private SystemUtils() { - - } - - public static final String OS_NAME = System.getProperty("os.name"); - - private static boolean isLinuxPlatform = false; - - static { - if (OS_NAME != null && OS_NAME.toLowerCase().indexOf("linux") >= 0) { - isLinuxPlatform = true; - } - } - public static final String JAVA_VERSION = System - .getProperty("java.version"); - private static boolean isAfterJava6u4Version = false; - static { - if (JAVA_VERSION != null) { - // java4 or java5 - if (JAVA_VERSION.indexOf("1.4.") >= 0 - || JAVA_VERSION.indexOf("1.5.") >= 0) { - isAfterJava6u4Version = false; - } else if (JAVA_VERSION.indexOf("1.6.") >= 0) { - int index = JAVA_VERSION.indexOf("_"); - if (index > 0) { - String subVersionStr = JAVA_VERSION.substring(index + 1); - if (subVersionStr != null && subVersionStr.length() > 0) { - try { - int subVersion = Integer.parseInt(subVersionStr); - if (subVersion >= 4) { - isAfterJava6u4Version = true; - } - } catch (NumberFormatException e) { - - } - } - } - // after java6 - } else { - isAfterJava6u4Version = true; - } - } - } - - public static final boolean isLinuxPlatform() { - return isLinuxPlatform; - } - - public static final boolean isAfterJava6u4Version() { - return isAfterJava6u4Version; - } - - public static void main(String[] args) { - System.out.println(isAfterJava6u4Version()); - } - - public static final int getSystemThreadCount() { - int cpus = getCpuProcessorCount(); - if (cpus <= 8) { - return cpus; - } else { - return 8 + (cpus - 8) * 5 / 8; - } - } - - public static final int getCpuProcessorCount() { - return Runtime.getRuntime().availableProcessors(); - } - - public static final Selector openSelector() throws IOException { - Selector result = null; - // check if it is linux os - if (SystemUtils.isLinuxPlatform()) { - try { - Class providerClazz = Class - .forName("sun.nio.ch.EPollSelectorProvider"); - if (providerClazz != null) { - try { - Method method = providerClazz.getMethod("provider"); - if (method != null) { - SelectorProvider selectorProvider = (SelectorProvider) method - .invoke(null); - if (selectorProvider != null) { - result = selectorProvider.openSelector(); - } - } - } catch (Exception e) { - // ignore - } - } - } catch (Exception e) { - // ignore - } - } - if (result == null) { - result = Selector.open(); - } - return result; - - } - - public static final String getRawAddress( - InetSocketAddress inetSocketAddress) { - InetAddress address = inetSocketAddress.getAddress(); - return address != null - ? address.getHostAddress() - : inetSocketAddress.getHostName(); - } - - public static final Queue createTransferQueue() { - try { - return (Queue) Class - .forName("java.util.concurrent.LinkedTransferQueue") - .newInstance(); - } catch (Exception e) { - return new LinkedTransferQueue(); - } - } - - public static Random createRandom() { - return new Random(); - } -} +/** + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 + */ +/** + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.util; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.nio.channels.Selector; +import java.nio.channels.spi.SelectorProvider; +import java.util.Queue; +import java.util.Random; + +/** + * System utils + * + * @author dennis + * + */ +public final class SystemUtils { + + private SystemUtils() { + + } + + public static final String OS_NAME = System.getProperty("os.name"); + + private static boolean isLinuxPlatform = false; + + static { + if (OS_NAME != null && OS_NAME.toLowerCase().indexOf("linux") >= 0) { + isLinuxPlatform = true; + } + } + public static final String JAVA_VERSION = System.getProperty("java.version"); + private static boolean isAfterJava6u4Version = false; + static { + if (JAVA_VERSION != null) { + // java4 or java5 + if (JAVA_VERSION.indexOf("1.4.") >= 0 || JAVA_VERSION.indexOf("1.5.") >= 0) { + isAfterJava6u4Version = false; + } else if (JAVA_VERSION.indexOf("1.6.") >= 0) { + int index = JAVA_VERSION.indexOf("_"); + if (index > 0) { + String subVersionStr = JAVA_VERSION.substring(index + 1); + if (subVersionStr != null && subVersionStr.length() > 0) { + try { + int subVersion = Integer.parseInt(subVersionStr); + if (subVersion >= 4) { + isAfterJava6u4Version = true; + } + } catch (NumberFormatException e) { + + } + } + } + // after java6 + } else { + isAfterJava6u4Version = true; + } + } + } + + public static final boolean isLinuxPlatform() { + return isLinuxPlatform; + } + + public static final boolean isAfterJava6u4Version() { + return isAfterJava6u4Version; + } + + public static void main(String[] args) { + System.out.println(isAfterJava6u4Version()); + } + + public static final int getSystemThreadCount() { + int cpus = getCpuProcessorCount(); + if (cpus <= 8) { + return cpus; + } else { + return 8 + (cpus - 8) * 5 / 8; + } + } + + public static final int getCpuProcessorCount() { + return Runtime.getRuntime().availableProcessors(); + } + + public static final Selector openSelector() throws IOException { + Selector result = null; + // check if it is linux os + if (SystemUtils.isLinuxPlatform()) { + try { + Class providerClazz = Class.forName("sun.nio.ch.EPollSelectorProvider"); + if (providerClazz != null) { + try { + Method method = providerClazz.getMethod("provider"); + if (method != null) { + SelectorProvider selectorProvider = (SelectorProvider) method.invoke(null); + if (selectorProvider != null) { + result = selectorProvider.openSelector(); + } + } + } catch (Exception e) { + // ignore + } + } + } catch (Exception e) { + // ignore + } + } + if (result == null) { + result = Selector.open(); + } + return result; + + } + + public static final String getRawAddress(InetSocketAddress inetSocketAddress) { + InetAddress address = inetSocketAddress.getAddress(); + return address != null ? address.getHostAddress() : inetSocketAddress.getHostName(); + } + + public static final Queue createTransferQueue() { + try { + return (Queue) Class.forName("java.util.concurrent.LinkedTransferQueue").newInstance(); + } catch (Exception e) { + return new LinkedTransferQueue(); + } + } + + public static Random createRandom() { + return new Random(); + } +} diff --git a/src/main/java/com/google/code/yanf4j/util/TransferQueue.java b/src/main/java/com/google/code/yanf4j/util/TransferQueue.java index 4c79da476..da550ef0e 100644 --- a/src/main/java/com/google/code/yanf4j/util/TransferQueue.java +++ b/src/main/java/com/google/code/yanf4j/util/TransferQueue.java @@ -1,131 +1,101 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ -package com.google.code.yanf4j.util; -import java.util.concurrent.*; - -/** - * A {@link BlockingQueue} in which producers may wait for consumers to receive - * elements. A {@code TransferQueue} may be useful for example in message - * passing applications in which producers sometimes (using method - * {@code transfer}) await receipt of elements by consumers invoking - * {@code take} or {@code poll}, while at other times enqueue elements (via - * method {@code put}) without waiting for receipt. Non-blocking and time-out - * versions of {@code tryTransfer} are also available. A TransferQueue may also - * be queried via {@code hasWaitingConsumer} whether there are any threads - * waiting for items, which is a converse analogy to a {@code peek} operation. - * - *

- * Like any {@code BlockingQueue}, a {@code TransferQueue} may be capacity - * bounded. If so, an attempted {@code transfer} operation may initially block - * waiting for available space, and/or subsequently block waiting for reception - * by a consumer. Note that in a queue with zero capacity, such as - * {@link SynchronousQueue}, {@code put} and {@code transfer} are effectively - * synonymous. - * - *

- * This interface is a member of the - * Java - * Collections Framework. - * - * @since 1.7 - * @author Doug Lea - * @param - * the type of elements held in this collection - */ -public interface TransferQueue extends BlockingQueue { - /** - * Transfers the specified element if there exists a consumer already - * waiting to receive it, otherwise returning {@code false} without - * enqueuing the element. - * - * @param e - * the element to transfer - * @return {@code true} if the element was transferred, else {@code false} - * @throws ClassCastException - * if the class of the specified element prevents it from being - * added to this queue - * @throws NullPointerException - * if the specified element is null - * @throws IllegalArgumentException - * if some property of the specified element prevents it from - * being added to this queue - */ - boolean tryTransfer(E e); - - /** - * Inserts the specified element into this queue, waiting if necessary for - * space to become available and the element to be dequeued by a consumer - * invoking {@code take} or {@code poll}. - * - * @param e - * the element to transfer - * @throws InterruptedException - * if interrupted while waiting, in which case the element is - * not enqueued. - * @throws ClassCastException - * if the class of the specified element prevents it from being - * added to this queue - * @throws NullPointerException - * if the specified element is null - * @throws IllegalArgumentException - * if some property of the specified element prevents it from - * being added to this queue - */ - void transfer(E e) throws InterruptedException; - - /** - * Inserts the specified element into this queue, waiting up to the - * specified wait time if necessary for space to become available and the - * element to be dequeued by a consumer invoking {@code take} or - * {@code poll}. - * - * @param e - * the element to transfer - * @param timeout - * how long to wait before giving up, in units of {@code unit} - * @param unit - * a {@code TimeUnit} determining how to interpret the - * {@code timeout} parameter - * @return {@code true} if successful, or {@code false} if the specified - * waiting time elapses before completion, in which case the element - * is not enqueued. - * @throws InterruptedException - * if interrupted while waiting, in which case the element is - * not enqueued. - * @throws ClassCastException - * if the class of the specified element prevents it from being - * added to this queue - * @throws NullPointerException - * if the specified element is null - * @throws IllegalArgumentException - * if some property of the specified element prevents it from - * being added to this queue - */ - boolean tryTransfer(E e, long timeout, TimeUnit unit) - throws InterruptedException; - - /** - * Returns {@code true} if there is at least one consumer waiting to dequeue - * an element via {@code take} or {@code poll}. The return value represents - * a momentary state of affairs. - * - * @return {@code true} if there is at least one waiting consumer - */ - boolean hasWaitingConsumer(); - - /** - * Returns an estimate of the number of consumers waiting to dequeue - * elements via {@code take} or {@code poll}. The return value is an - * approximation of a momentary state of affairs, that may be inaccurate if - * consumers have completed or given up waiting. The value may be useful for - * monitoring and heuristics, but not for synchronization control. - * Implementations of this method are likely to be noticeably slower than - * those for {@link #hasWaitingConsumer}. - * - * @return the number of consumers waiting to dequeue elements - */ - int getWaitingConsumerCount(); -} +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 Expert Group and released to the + * public domain, as explained at http://creativecommons.org/licenses/publicdomain + */ +package com.google.code.yanf4j.util; + +import java.util.concurrent.*; + +/** + * A {@link BlockingQueue} in which producers may wait for consumers to receive elements. A + * {@code TransferQueue} may be useful for example in message passing applications in which + * producers sometimes (using method {@code transfer}) await receipt of elements by consumers + * invoking {@code take} or {@code poll}, while at other times enqueue elements (via method + * {@code put}) without waiting for receipt. Non-blocking and time-out versions of + * {@code tryTransfer} are also available. A TransferQueue may also be queried via + * {@code hasWaitingConsumer} whether there are any threads waiting for items, which is a converse + * analogy to a {@code peek} operation. + * + *

+ * Like any {@code BlockingQueue}, a {@code TransferQueue} may be capacity bounded. If so, an + * attempted {@code transfer} operation may initially block waiting for available space, and/or + * subsequently block waiting for reception by a consumer. Note that in a queue with zero capacity, + * such as {@link SynchronousQueue}, {@code put} and {@code transfer} are effectively synonymous. + * + *

+ * This interface is a member of the + * Java Collections Framework. + * + * @since 1.7 + * @author Doug Lea + * @param the type of elements held in this collection + */ +public interface TransferQueue extends BlockingQueue { + /** + * Transfers the specified element if there exists a consumer already waiting to receive it, + * otherwise returning {@code false} without enqueuing the element. + * + * @param e the element to transfer + * @return {@code true} if the element was transferred, else {@code false} + * @throws ClassCastException if the class of the specified element prevents it from being added + * to this queue + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified element prevents it from + * being added to this queue + */ + boolean tryTransfer(E e); + + /** + * Inserts the specified element into this queue, waiting if necessary for space to become + * available and the element to be dequeued by a consumer invoking {@code take} or {@code poll}. + * + * @param e the element to transfer + * @throws InterruptedException if interrupted while waiting, in which case the element is not + * enqueued. + * @throws ClassCastException if the class of the specified element prevents it from being added + * to this queue + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified element prevents it from + * being added to this queue + */ + void transfer(E e) throws InterruptedException; + + /** + * Inserts the specified element into this queue, waiting up to the specified wait time if + * necessary for space to become available and the element to be dequeued by a consumer invoking + * {@code take} or {@code poll}. + * + * @param e the element to transfer + * @param timeout how long to wait before giving up, in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter + * @return {@code true} if successful, or {@code false} if the specified waiting time elapses + * before completion, in which case the element is not enqueued. + * @throws InterruptedException if interrupted while waiting, in which case the element is not + * enqueued. + * @throws ClassCastException if the class of the specified element prevents it from being added + * to this queue + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified element prevents it from + * being added to this queue + */ + boolean tryTransfer(E e, long timeout, TimeUnit unit) throws InterruptedException; + + /** + * Returns {@code true} if there is at least one consumer waiting to dequeue an element via + * {@code take} or {@code poll}. The return value represents a momentary state of affairs. + * + * @return {@code true} if there is at least one waiting consumer + */ + boolean hasWaitingConsumer(); + + /** + * Returns an estimate of the number of consumers waiting to dequeue elements via {@code take} or + * {@code poll}. The return value is an approximation of a momentary state of affairs, that may be + * inaccurate if consumers have completed or given up waiting. The value may be useful for + * monitoring and heuristics, but not for synchronization control. Implementations of this method + * are likely to be noticeably slower than those for {@link #hasWaitingConsumer}. + * + * @return the number of consumers waiting to dequeue elements + */ + int getWaitingConsumerCount(); +} diff --git a/src/main/java/com/google/code/yanf4j/util/WorkerThreadFactory.java b/src/main/java/com/google/code/yanf4j/util/WorkerThreadFactory.java index 2244ee6c5..571b59428 100644 --- a/src/main/java/com/google/code/yanf4j/util/WorkerThreadFactory.java +++ b/src/main/java/com/google/code/yanf4j/util/WorkerThreadFactory.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 com.google.code.yanf4j.util; @@ -32,45 +26,40 @@ * */ public class WorkerThreadFactory implements ThreadFactory { - private static final AtomicInteger poolNumber = new AtomicInteger(1); - private final ThreadGroup group; - private final AtomicInteger threadNumber = new AtomicInteger(1); - private final String namePrefix; + private static final AtomicInteger poolNumber = new AtomicInteger(1); + private final ThreadGroup group; + private final AtomicInteger threadNumber = new AtomicInteger(1); + private final String namePrefix; - public WorkerThreadFactory(ThreadGroup group, String prefix) { - if (group == null) { - SecurityManager s = System.getSecurityManager(); - this.group = (s != null) - ? s.getThreadGroup() - : Thread.currentThread().getThreadGroup(); - } else { - this.group = group; - } - if (prefix == null) { - this.namePrefix = "pool-" + poolNumber.getAndIncrement() - + "-thread-"; - } else { - this.namePrefix = prefix + "-" + poolNumber.getAndIncrement() - + "-thread-"; - } - } + public WorkerThreadFactory(ThreadGroup group, String prefix) { + if (group == null) { + SecurityManager s = System.getSecurityManager(); + this.group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); + } else { + this.group = group; + } + if (prefix == null) { + this.namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-"; + } else { + this.namePrefix = prefix + "-" + poolNumber.getAndIncrement() + "-thread-"; + } + } - public WorkerThreadFactory(String prefix) { - this(null, prefix); - } + public WorkerThreadFactory(String prefix) { + this(null, prefix); + } - public WorkerThreadFactory() { - this(null, null); - } + public WorkerThreadFactory() { + this(null, null); + } - public Thread newThread(Runnable r) { - Thread t = new Thread(this.group, r, - this.namePrefix + this.threadNumber.getAndIncrement(), 0); - t.setDaemon(true); - if (t.getPriority() != Thread.NORM_PRIORITY) { - t.setPriority(Thread.NORM_PRIORITY); - } - return t; - } + public Thread newThread(Runnable r) { + Thread t = new Thread(this.group, r, this.namePrefix + this.threadNumber.getAndIncrement(), 0); + t.setDaemon(true); + if (t.getPriority() != Thread.NORM_PRIORITY) { + t.setPriority(Thread.NORM_PRIORITY); + } + return t; + } } diff --git a/src/main/java/com/google/code/yanf4j/util/package.html b/src/main/java/com/google/code/yanf4j/util/package.html index 82bbf06e3..defb1f73c 100644 --- a/src/main/java/com/google/code/yanf4j/util/package.html +++ b/src/main/java/com/google/code/yanf4j/util/package.html @@ -1,14 +1,10 @@ - - + - -Yanf4j utilities - - - -

Yanf4j utilities

- - - + + Yanf4j utilities + + +

Yanf4j utilities

+ + \ No newline at end of file diff --git a/src/main/java/net/rubyeye/xmemcached/CASOperation.java b/src/main/java/net/rubyeye/xmemcached/CASOperation.java index 13da74642..ac73e411f 100644 --- a/src/main/java/net/rubyeye/xmemcached/CASOperation.java +++ b/src/main/java/net/rubyeye/xmemcached/CASOperation.java @@ -1,13 +1,10 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached; @@ -18,20 +15,19 @@ * */ public interface CASOperation { - /** - * Max retry times,If retry times is great than this value,xmemcached will - * throw TimeoutException - * - * @return - */ - public int getMaxTries(); + /** + * Max retry times,If retry times is great than this value,xmemcached will throw TimeoutException + * + * @return + */ + public int getMaxTries(); - /** - * Return the new value which you want to cas - * - * @param currentCAS - * @param currentValue - * @return expected new value - */ - public T getNewValue(long currentCAS, T currentValue); + /** + * Return the new value which you want to cas + * + * @param currentCAS + * @param currentValue + * @return expected new value + */ + public T getNewValue(long currentCAS, T currentValue); } diff --git a/src/main/java/net/rubyeye/xmemcached/CommandFactory.java b/src/main/java/net/rubyeye/xmemcached/CommandFactory.java index 455e2eda5..051082f49 100644 --- a/src/main/java/net/rubyeye/xmemcached/CommandFactory.java +++ b/src/main/java/net/rubyeye/xmemcached/CommandFactory.java @@ -1,31 +1,24 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached; import java.net.InetSocketAddress; import java.util.Collection; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.buffer.BufferAllocator; import net.rubyeye.xmemcached.command.Command; import net.rubyeye.xmemcached.command.CommandType; @@ -35,282 +28,263 @@ @SuppressWarnings("unchecked") public interface CommandFactory { - /** - * set command factory's buffer allocator - * - * @since 1.2.0 - * @param bufferAllocator - */ - public void setBufferAllocator(BufferAllocator bufferAllocator); + /** + * set command factory's buffer allocator + * + * @since 1.2.0 + * @param bufferAllocator + */ + public void setBufferAllocator(BufferAllocator bufferAllocator); - /** - * create a delete command - * - * @param key - * @param time - * @return - */ - public Command createDeleteCommand(final String key, final byte[] keyBytes, - final int time, long cas, boolean noreply); + /** + * create a delete command + * + * @param key + * @param time + * @return + */ + public Command createDeleteCommand(final String key, final byte[] keyBytes, final int time, + long cas, boolean noreply); - /** - * create a version command - * - * @return - */ - public Command createVersionCommand(CountDownLatch latch, - InetSocketAddress server); + /** + * create a version command + * + * @return + */ + public Command createVersionCommand(CountDownLatch latch, InetSocketAddress server); - /** - * create a flush_all command - * - * @return - */ - public Command createFlushAllCommand(CountDownLatch latch, int delay, - boolean noreply); + /** + * create a flush_all command + * + * @return + */ + public Command createFlushAllCommand(CountDownLatch latch, int delay, boolean noreply); - /** - * create a stats command - * - * @return - */ - public Command createStatsCommand(InetSocketAddress server, - CountDownLatch latch, String itemName); + /** + * create a stats command + * + * @return + */ + public Command createStatsCommand(InetSocketAddress server, CountDownLatch latch, + String itemName); - /** - * create a get/gets command - * - * @param key - * @param keyBytes - * @param cmdType - * 命令类型 - * @param transcoder - * TODO - * @param cmdBytes - * 命令的字节数组,如"get".getBytes() - * @return - */ + /** + * create a get/gets command + * + * @param key + * @param keyBytes + * @param cmdType 命令类型 + * @param transcoder TODO + * @param cmdBytes 命令的字节数组,如"get".getBytes() + * @return + */ - public Command createGetCommand(final String key, final byte[] keyBytes, - final CommandType cmdType, Transcoder transcoder); + public Command createGetCommand(final String key, final byte[] keyBytes, + final CommandType cmdType, Transcoder transcoder); - /** - * Create a multi-get command - * - * @param - * @param keys - * @param latch - * @param result - * @param cmdBytes - * @param cmdType - * @param transcoder - * @return - */ - public Command createGetMultiCommand(Collection keys, - CountDownLatch latch, CommandType cmdType, - Transcoder transcoder); + /** + * Create a multi-get command + * + * @param + * @param keys + * @param latch + * @param result + * @param cmdBytes + * @param cmdType + * @param transcoder + * @return + */ + public Command createGetMultiCommand(Collection keys, CountDownLatch latch, + CommandType cmdType, Transcoder transcoder); - /** - * create a incr/decr command - * - * @param key - * @param keyBytes - * @param delta - * @param initial - * @param expTime - * @param cmdType - * @param noreply - * @return - */ - public Command createIncrDecrCommand(final String key, - final byte[] keyBytes, final long delta, long initial, int expTime, - CommandType cmdType, boolean noreply); + /** + * create a incr/decr command + * + * @param key + * @param keyBytes + * @param delta + * @param initial + * @param expTime + * @param cmdType + * @param noreply + * @return + */ + public Command createIncrDecrCommand(final String key, final byte[] keyBytes, final long delta, + long initial, int expTime, CommandType cmdType, boolean noreply); - /** - * Create a cas command - * - * @param key - * @param keyBytes - * @param exp - * @param value - * @param cas - * @param noreply - * @param transcoder - * @return - */ - public Command createCASCommand(final String key, final byte[] keyBytes, - final int exp, final Object value, long cas, boolean noreply, - Transcoder transcoder); + /** + * Create a cas command + * + * @param key + * @param keyBytes + * @param exp + * @param value + * @param cas + * @param noreply + * @param transcoder + * @return + */ + public Command createCASCommand(final String key, final byte[] keyBytes, final int exp, + final Object value, long cas, boolean noreply, Transcoder transcoder); - /** - * Create a set command - * - * @param key - * @param keyBytes - * @param exp - * @param value - * @param noreply - * @param transcoder - * @return - */ - public Command createSetCommand(final String key, final byte[] keyBytes, - final int exp, final Object value, boolean noreply, - Transcoder transcoder); + /** + * Create a set command + * + * @param key + * @param keyBytes + * @param exp + * @param value + * @param noreply + * @param transcoder + * @return + */ + public Command createSetCommand(final String key, final byte[] keyBytes, final int exp, + final Object value, boolean noreply, Transcoder transcoder); - /** - * create a add command - * - * @param key - * @param keyBytes - * @param exp - * @param value - * @param noreply - * @param transcoder - * @return - */ - public Command createAddCommand(final String key, final byte[] keyBytes, - final int exp, final Object value, boolean noreply, - Transcoder transcoder); + /** + * create a add command + * + * @param key + * @param keyBytes + * @param exp + * @param value + * @param noreply + * @param transcoder + * @return + */ + public Command createAddCommand(final String key, final byte[] keyBytes, final int exp, + final Object value, boolean noreply, Transcoder transcoder); - /** - * create a replace command - * - * @param key - * @param keyBytes - * @param exp - * @param value - * @param noreply - * @param transcoder - * @return - */ - public Command createReplaceCommand(final String key, final byte[] keyBytes, - final int exp, final Object value, boolean noreply, - Transcoder transcoder); + /** + * create a replace command + * + * @param key + * @param keyBytes + * @param exp + * @param value + * @param noreply + * @param transcoder + * @return + */ + public Command createReplaceCommand(final String key, final byte[] keyBytes, final int exp, + final Object value, boolean noreply, Transcoder transcoder); - /** - * create a append command - * - * @param key - * @param keyBytes - * @param value - * @param noreply - * @param transcoder - * @return - */ - public Command createAppendCommand(final String key, final byte[] keyBytes, - final Object value, boolean noreply, Transcoder transcoder); + /** + * create a append command + * + * @param key + * @param keyBytes + * @param value + * @param noreply + * @param transcoder + * @return + */ + public Command createAppendCommand(final String key, final byte[] keyBytes, final Object value, + boolean noreply, Transcoder transcoder); - /** - * Create a prepend command - * - * @param key - * @param keyBytes - * @param value - * @param noreply - * @param transcoder - * @return - */ - public Command createPrependCommand(final String key, final byte[] keyBytes, - final Object value, boolean noreply, Transcoder transcoder); + /** + * Create a prepend command + * + * @param key + * @param keyBytes + * @param value + * @param noreply + * @param transcoder + * @return + */ + public Command createPrependCommand(final String key, final byte[] keyBytes, final Object value, + boolean noreply, Transcoder transcoder); - /** - * Create a verbosity command - * - * @param latch - * @param level - * @param noreply - * @return - */ - public Command createVerbosityCommand(CountDownLatch latch, int level, - boolean noreply); + /** + * Create a verbosity command + * + * @param latch + * @param level + * @param noreply + * @return + */ + public Command createVerbosityCommand(CountDownLatch latch, int level, boolean noreply); - /** - * Create a command for listing authentication mechanisms - * - * @param latch - * @return - */ - public Command createAuthListMechanismsCommand(CountDownLatch latch); + /** + * Create a command for listing authentication mechanisms + * + * @param latch + * @return + */ + public Command createAuthListMechanismsCommand(CountDownLatch latch); - /** - * Create command for starting authentication - * - * @param mechanism - * @param latch - * @param authData - * @return - */ - public Command createAuthStartCommand(String mechanism, - CountDownLatch latch, byte[] authData); + /** + * Create command for starting authentication + * + * @param mechanism + * @param latch + * @param authData + * @return + */ + public Command createAuthStartCommand(String mechanism, CountDownLatch latch, byte[] authData); - /** - * Create a command for stepping authentication - * - * @param mechanism - * @param latch - * @param authData - * @return - */ - public Command createAuthStepCommand(String mechanism, CountDownLatch latch, - byte[] authData); + /** + * Create a command for stepping authentication + * + * @param mechanism + * @param latch + * @param authData + * @return + */ + public Command createAuthStepCommand(String mechanism, CountDownLatch latch, byte[] authData); - /** - * create a quit command - * - * @return - */ - public Command createQuitCommand(); + /** + * create a quit command + * + * @return + */ + public Command createQuitCommand(); - /** - * Create a touch command - * - * @since 1.3.3 - * @param key - * @param keyBytes - * @param latch - * TODO - * @param exp - * @param noreply - * @return - */ - public Command createTouchCommand(final String key, final byte[] keyBytes, - CountDownLatch latch, int exp, boolean noreply); + /** + * Create a touch command + * + * @since 1.3.3 + * @param key + * @param keyBytes + * @param latch TODO + * @param exp + * @param noreply + * @return + */ + public Command createTouchCommand(final String key, final byte[] keyBytes, CountDownLatch latch, + int exp, boolean noreply); - /** - * Create a get-and-touch command - * - * @since 1.3.3 - * @param key - * @param keyBytes - * @param latch - * TODO - * @param exp - * @param noreply - * @return - */ - public Command createGetAndTouchCommand(final String key, - final byte[] keyBytes, CountDownLatch latch, int exp, - boolean noreply); + /** + * Create a get-and-touch command + * + * @since 1.3.3 + * @param key + * @param keyBytes + * @param latch TODO + * @param exp + * @param noreply + * @return + */ + public Command createGetAndTouchCommand(final String key, final byte[] keyBytes, + CountDownLatch latch, int exp, boolean noreply); - /** - * Create a AWS ElasticCache config command, only supports Cache Engine - * Version 1.4.14 or Higher. - * - * @see Adding - * Auto Discovery To Your Client Library - * @param subCommand - * @param key - * @return - */ - public Command createAWSElasticCacheConfigCommand(String subCommand, - String key); + /** + * Create a AWS ElasticCache config command, only supports Cache Engine Version 1.4.14 or Higher. + * + * @see Adding + * Auto Discovery To Your Client Library + * @param subCommand + * @param key + * @return + */ + public Command createAWSElasticCacheConfigCommand(String subCommand, String key); - /** - * Get this client's protocol version - * - * @return - */ - public Protocol getProtocol(); + /** + * Get this client's protocol version + * + * @return + */ + public Protocol getProtocol(); -} \ No newline at end of file +} diff --git a/src/main/java/net/rubyeye/xmemcached/Counter.java b/src/main/java/net/rubyeye/xmemcached/Counter.java index 80a2e4451..513fb12ab 100644 --- a/src/main/java/net/rubyeye/xmemcached/Counter.java +++ b/src/main/java/net/rubyeye/xmemcached/Counter.java @@ -1,7 +1,6 @@ package net.rubyeye.xmemcached; import java.util.concurrent.TimeoutException; - import net.rubyeye.xmemcached.exception.MemcachedClientException; import net.rubyeye.xmemcached.exception.MemcachedException; @@ -12,148 +11,139 @@ * */ public final class Counter { - private final MemcachedClient memcachedClient; - private final String key; - private final long initialValue; + private final MemcachedClient memcachedClient; + private final String key; + private final long initialValue; - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result - + ((this.key == null) ? 0 : this.key.hashCode()); - result = prime * result + ((this.memcachedClient == null) - ? 0 - : this.memcachedClient.hashCode()); - return result; - } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.key == null) ? 0 : this.key.hashCode()); + result = + prime * result + ((this.memcachedClient == null) ? 0 : this.memcachedClient.hashCode()); + return result; + } - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - Counter other = (Counter) obj; - if (this.key == null) { - if (other.key != null) { - return false; - } - } else if (!this.key.equals(other.key)) { - return false; - } - if (this.memcachedClient == null) { - if (other.memcachedClient != null) { - return false; - } - } else if (!this.memcachedClient.equals(other.memcachedClient)) { - return false; - } - return true; - } + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + Counter other = (Counter) obj; + if (this.key == null) { + if (other.key != null) { + return false; + } + } else if (!this.key.equals(other.key)) { + return false; + } + if (this.memcachedClient == null) { + if (other.memcachedClient != null) { + return false; + } + } else if (!this.memcachedClient.equals(other.memcachedClient)) { + return false; + } + return true; + } - public final String getKey() { - return this.key; - } + public final String getKey() { + return this.key; + } - /** - * Get current value - * - * @return - * @throws MemcachedException - * @throws InterruptedException - * @throws TimeoutException - */ - public long get() - throws MemcachedException, InterruptedException, TimeoutException { - Object result = this.memcachedClient.get(this.key); - if (result == null) { - throw new MemcachedClientException("key is not existed."); - } else { - if (result instanceof Long) - return (Long) result; - else - return Long.valueOf(((String) result).trim()); - } - } + /** + * Get current value + * + * @return + * @throws MemcachedException + * @throws InterruptedException + * @throws TimeoutException + */ + public long get() throws MemcachedException, InterruptedException, TimeoutException { + Object result = this.memcachedClient.get(this.key); + if (result == null) { + throw new MemcachedClientException("key is not existed."); + } else { + if (result instanceof Long) + return (Long) result; + else + return Long.valueOf(((String) result).trim()); + } + } - /** - * Set counter's value to expected. - * - * @param value - * @throws MemcachedException - * @throws InterruptedException - * @throws TimeoutException - */ - public void set(long value) - throws MemcachedException, InterruptedException, TimeoutException { - this.memcachedClient.set(this.key, 0, String.valueOf(value)); - } + /** + * Set counter's value to expected. + * + * @param value + * @throws MemcachedException + * @throws InterruptedException + * @throws TimeoutException + */ + public void set(long value) throws MemcachedException, InterruptedException, TimeoutException { + this.memcachedClient.set(this.key, 0, String.valueOf(value)); + } - public Counter(MemcachedClient memcachedClient, String key, - long initialValue) { - super(); - this.memcachedClient = memcachedClient; - this.key = key; - this.initialValue = initialValue; - try { - this.memcachedClient.add(key, 0, String.valueOf(this.initialValue)); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } catch (Exception e) { - throw new IllegalStateException("Initialize counter failed", e); - } - } + public Counter(MemcachedClient memcachedClient, String key, long initialValue) { + super(); + this.memcachedClient = memcachedClient; + this.key = key; + this.initialValue = initialValue; + try { + this.memcachedClient.add(key, 0, String.valueOf(this.initialValue)); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } catch (Exception e) { + throw new IllegalStateException("Initialize counter failed", e); + } + } - /** - * Increase value by one - * - * @return - * @throws MemcachedException - * @throws InterruptedException - * @throws TimeoutException - */ - public long incrementAndGet() - throws MemcachedException, InterruptedException, TimeoutException { - return this.memcachedClient.incr(this.key, 1, this.initialValue); - } + /** + * Increase value by one + * + * @return + * @throws MemcachedException + * @throws InterruptedException + * @throws TimeoutException + */ + public long incrementAndGet() throws MemcachedException, InterruptedException, TimeoutException { + return this.memcachedClient.incr(this.key, 1, this.initialValue); + } - /** - * Decrease value by one - * - * @return - * @throws MemcachedException - * @throws InterruptedException - * @throws TimeoutException - */ - public long decrementAndGet() - throws MemcachedException, InterruptedException, TimeoutException { - return this.memcachedClient.decr(this.key, 1, this.initialValue); - } + /** + * Decrease value by one + * + * @return + * @throws MemcachedException + * @throws InterruptedException + * @throws TimeoutException + */ + public long decrementAndGet() throws MemcachedException, InterruptedException, TimeoutException { + return this.memcachedClient.decr(this.key, 1, this.initialValue); + } - /** - * Add value and get the result - * - * @param delta - * @return - * @throws MemcachedException - * @throws InterruptedException - * @throws TimeoutException - */ - public long addAndGet(long delta) - throws MemcachedException, InterruptedException, TimeoutException { - if (delta >= 0) { - return this.memcachedClient.incr(this.key, delta, - this.initialValue); - } else { - return this.memcachedClient.decr(this.key, -delta, - this.initialValue); - } - } + /** + * Add value and get the result + * + * @param delta + * @return + * @throws MemcachedException + * @throws InterruptedException + * @throws TimeoutException + */ + public long addAndGet(long delta) + throws MemcachedException, InterruptedException, TimeoutException { + if (delta >= 0) { + return this.memcachedClient.incr(this.key, delta, this.initialValue); + } else { + return this.memcachedClient.decr(this.key, -delta, this.initialValue); + } + } } diff --git a/src/main/java/net/rubyeye/xmemcached/FlowControl.java b/src/main/java/net/rubyeye/xmemcached/FlowControl.java index 6bf9aaf59..adc0e4b7b 100644 --- a/src/main/java/net/rubyeye/xmemcached/FlowControl.java +++ b/src/main/java/net/rubyeye/xmemcached/FlowControl.java @@ -1,37 +1,37 @@ -package net.rubyeye.xmemcached; - -import java.util.concurrent.Semaphore; - -/** - * Flow control for noreply operations. - * - * @author dennis - * @since 1.3.8 - * - */ -public class FlowControl { - private Semaphore permits; - private int max; - - public FlowControl(int permits) { - super(); - this.max = permits; - this.permits = new Semaphore(permits); - } - - public int max() { - return this.max; - } - - public int permits() { - return this.permits.availablePermits(); - } - - public boolean aquire() { - return this.permits.tryAcquire(); - } - - public void release() { - this.permits.release(); - } -} +package net.rubyeye.xmemcached; + +import java.util.concurrent.Semaphore; + +/** + * Flow control for noreply operations. + * + * @author dennis + * @since 1.3.8 + * + */ +public class FlowControl { + private Semaphore permits; + private int max; + + public FlowControl(int permits) { + super(); + this.max = permits; + this.permits = new Semaphore(permits); + } + + public int max() { + return this.max; + } + + public int permits() { + return this.permits.availablePermits(); + } + + public boolean aquire() { + return this.permits.tryAcquire(); + } + + public void release() { + this.permits.release(); + } +} diff --git a/src/main/java/net/rubyeye/xmemcached/GetsResponse.java b/src/main/java/net/rubyeye/xmemcached/GetsResponse.java index c9e80f716..4c16107e0 100644 --- a/src/main/java/net/rubyeye/xmemcached/GetsResponse.java +++ b/src/main/java/net/rubyeye/xmemcached/GetsResponse.java @@ -1,13 +1,10 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached; @@ -18,62 +15,61 @@ * */ public final class GetsResponse { - private final long cas; - private final T value; + private final long cas; + private final T value; - public GetsResponse(final long cas, final T value) { - super(); - this.cas = cas; - this.value = value; - } + public GetsResponse(final long cas, final T value) { + super(); + this.cas = cas; + this.value = value; + } - public long getCas() { - return this.cas; - } + public long getCas() { + return this.cas; + } - public T getValue() { - return this.value; - } + public T getValue() { + return this.value; + } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + (int) (this.cas ^ (this.cas >>> 32)); - result = prime * result - + ((this.value == null) ? 0 : this.value.hashCode()); - return result; - } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (int) (this.cas ^ (this.cas >>> 32)); + result = prime * result + ((this.value == null) ? 0 : this.value.hashCode()); + return result; + } - @Override - @SuppressWarnings("unchecked") - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - GetsResponse other = (GetsResponse) obj; - if (this.cas != other.cas) { - return false; - } - if (this.value == null) { - if (other.value != null) { - return false; - } - } else if (!this.value.equals(other.value)) { - return false; - } - return true; - } + @Override + @SuppressWarnings("unchecked") + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + GetsResponse other = (GetsResponse) obj; + if (this.cas != other.cas) { + return false; + } + if (this.value == null) { + if (other.value != null) { + return false; + } + } else if (!this.value.equals(other.value)) { + return false; + } + return true; + } - @Override - public String toString() { - return "GetsResponse[cas=" + this.cas + ",value=" + this.value + "]"; - } + @Override + public String toString() { + return "GetsResponse[cas=" + this.cas + ",value=" + this.value + "]"; + } } diff --git a/src/main/java/net/rubyeye/xmemcached/HashAlgorithm.java b/src/main/java/net/rubyeye/xmemcached/HashAlgorithm.java index 3acbd9eda..eafe96029 100644 --- a/src/main/java/net/rubyeye/xmemcached/HashAlgorithm.java +++ b/src/main/java/net/rubyeye/xmemcached/HashAlgorithm.java @@ -1,229 +1,223 @@ -package net.rubyeye.xmemcached; - -import java.io.UnsupportedEncodingException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.zip.CRC32; - -import net.rubyeye.xmemcached.exception.MemcachedClientException; -import net.rubyeye.xmemcached.utils.ByteUtils; - -/** - * Known hashing algorithms for locating a server for a key. Note that all hash - * algorithms return 64-bits of hash, but only the lower 32-bits are - * significant. This allows a positive 32-bit number to be returned for all - * cases. - */ -public enum HashAlgorithm { - - /** - * Native hash (String.hashCode()). - */ - NATIVE_HASH, - /** - * CRC32_HASH as used by the perl API. This will be more consistent both - * across multiple API users as well as java versions, but is mostly likely - * significantly slower. - */ - CRC32_HASH, - /** - * FNV hashes are designed to be fast while maintaining a low collision - * rate. The FNV speed allows one to quickly hash lots of data while - * maintaining a reasonable collision rate. - * - * @see http://www.isthe.com/chongo/tech/comp/fnv/ - * @see http://en.wikipedia.org/wiki/Fowler_Noll_Vo_hash - */ - FNV1_64_HASH, - /** - * Variation of FNV. - */ - FNV1A_64_HASH, - /** - * 32-bit FNV1. - */ - FNV1_32_HASH, - /** - * 32-bit FNV1a. - */ - FNV1A_32_HASH, - /** - * MD5-based hash algorithm used by ketama. - */ - KETAMA_HASH, - - /** - * From mysql source - */ - MYSQL_HASH, - - ELF_HASH, - - RS_HASH, - - /** - * From lua source,it is used for long key - */ - LUA_HASH, - - ELECTION_HASH, - /** - * The Jenkins One-at-a-time hash ,please see - * http://www.burtleburtle.net/bob/hash/doobs.html - */ - ONE_AT_A_TIME; - - private static final long FNV_64_INIT = 0xcbf29ce484222325L; - private static final long FNV_64_PRIME = 0x100000001b3L; - - private static final long FNV_32_INIT = 2166136261L; - private static final long FNV_32_PRIME = 16777619; - - /** - * Compute the hash for the given key. - * - * @return a positive integer hash - */ - public long hash(final String k) { - long rv = 0; - switch (this) { - case NATIVE_HASH : - rv = k.hashCode(); - break; - case CRC32_HASH : - // return (crc32(shift) >> 16) & 0x7fff; - CRC32 crc32 = new CRC32(); - crc32.update(ByteUtils.getBytes(k)); - rv = crc32.getValue() >> 16 & 0x7fff; - break; - case FNV1_64_HASH : { - // Thanks to pierre@demartines.com for the pointer - rv = FNV_64_INIT; - int len = k.length(); - for (int i = 0; i < len; i++) { - rv *= FNV_64_PRIME; - rv ^= k.charAt(i); - } - } - break; - case FNV1A_64_HASH : { - rv = FNV_64_INIT; - int len = k.length(); - for (int i = 0; i < len; i++) { - rv ^= k.charAt(i); - rv *= FNV_64_PRIME; - } - } - break; - case FNV1_32_HASH : { - rv = FNV_32_INIT; - int len = k.length(); - for (int i = 0; i < len; i++) { - rv *= FNV_32_PRIME; - rv ^= k.charAt(i); - } - } - break; - case FNV1A_32_HASH : { - rv = FNV_32_INIT; - int len = k.length(); - for (int i = 0; i < len; i++) { - rv ^= k.charAt(i); - rv *= FNV_32_PRIME; - } - } - break; - case ELECTION_HASH : - case KETAMA_HASH : - byte[] bKey = computeMd5(k); - rv = (long) (bKey[3] & 0xFF) << 24 - | (long) (bKey[2] & 0xFF) << 16 - | (long) (bKey[1] & 0xFF) << 8 | bKey[0] & 0xFF; - break; - - case MYSQL_HASH : - int nr2 = 4; - for (int i = 0; i < k.length(); i++) { - rv ^= ((rv & 63) + nr2) * k.charAt(i) + (rv << 8); - nr2 += 3; - } - break; - case ELF_HASH : - long x = 0; - for (int i = 0; i < k.length(); i++) { - rv = (rv << 4) + k.charAt(i); - if ((x = rv & 0xF0000000L) != 0) { - rv ^= x >> 24; - rv &= ~x; - } - } - rv = rv & 0x7FFFFFFF; - break; - case RS_HASH : - long b = 378551; - long a = 63689; - for (int i = 0; i < k.length(); i++) { - rv = rv * a + k.charAt(i); - a *= b; - } - rv = rv & 0x7FFFFFFF; - break; - case LUA_HASH : - int step = (k.length() >> 5) + 1; - rv = k.length(); - for (int len = k.length(); len >= step; len -= step) { - rv = rv ^ (rv << 5) + (rv >> 2) + k.charAt(len - 1); - } - break; - case ONE_AT_A_TIME : - try { - int hash = 0; - for (byte bt : k.getBytes("utf-8")) { - hash += (bt & 0xFF); - hash += (hash << 10); - hash ^= (hash >>> 6); - } - hash += (hash << 3); - hash ^= (hash >>> 11); - hash += (hash << 15); - rv = hash; - } catch (UnsupportedEncodingException e) { - throw new IllegalStateException("Hash function error", e); - } - break; - default : - assert false; - } - - return rv & 0xffffffffL; /* Convert to unsigned 32-bits */ - } - - private static ThreadLocal md5Local = new ThreadLocal(); - - /** - * Get the md5 of the given key. - */ - public static byte[] computeMd5(String k) { - MessageDigest md5 = md5Local.get(); - if (md5 == null) { - try { - md5 = MessageDigest.getInstance("MD5"); - md5Local.set(md5); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException("MD5 not supported", e); - } - } - md5.reset(); - md5.update(ByteUtils.getBytes(k)); - return md5.digest(); - } - - // public static void main(String[] args) { - // HashAlgorithm alg=HashAlgorithm.CRC32_HASH; - // long h=0; - // long start=System.currentTimeMillis(); - // for(int i=0;i<100000;i++) - // h=alg.hash("MYSQL_HASH"); - // System.out.println(System.currentTimeMillis()-start); - // } -} +package net.rubyeye.xmemcached; + +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.zip.CRC32; +import net.rubyeye.xmemcached.exception.MemcachedClientException; +import net.rubyeye.xmemcached.utils.ByteUtils; + +/** + * Known hashing algorithms for locating a server for a key. Note that all hash algorithms return + * 64-bits of hash, but only the lower 32-bits are significant. This allows a positive 32-bit number + * to be returned for all cases. + */ +public enum HashAlgorithm { + + /** + * Native hash (String.hashCode()). + */ + NATIVE_HASH, + /** + * CRC32_HASH as used by the perl API. This will be more consistent both across multiple API users + * as well as java versions, but is mostly likely significantly slower. + */ + CRC32_HASH, + /** + * FNV hashes are designed to be fast while maintaining a low collision rate. The FNV speed allows + * one to quickly hash lots of data while maintaining a reasonable collision rate. + * + * @see http://www.isthe.com/chongo/tech/comp/fnv/ + * @see http://en.wikipedia.org/wiki/Fowler_Noll_Vo_hash + */ + FNV1_64_HASH, + /** + * Variation of FNV. + */ + FNV1A_64_HASH, + /** + * 32-bit FNV1. + */ + FNV1_32_HASH, + /** + * 32-bit FNV1a. + */ + FNV1A_32_HASH, + /** + * MD5-based hash algorithm used by ketama. + */ + KETAMA_HASH, + + /** + * From mysql source + */ + MYSQL_HASH, + + ELF_HASH, + + RS_HASH, + + /** + * From lua source,it is used for long key + */ + LUA_HASH, + + ELECTION_HASH, + /** + * The Jenkins One-at-a-time hash ,please see http://www.burtleburtle.net/bob/hash/doobs.html + */ + ONE_AT_A_TIME; + + private static final long FNV_64_INIT = 0xcbf29ce484222325L; + private static final long FNV_64_PRIME = 0x100000001b3L; + + private static final long FNV_32_INIT = 2166136261L; + private static final long FNV_32_PRIME = 16777619; + + /** + * Compute the hash for the given key. + * + * @return a positive integer hash + */ + public long hash(final String k) { + long rv = 0; + switch (this) { + case NATIVE_HASH: + rv = k.hashCode(); + break; + case CRC32_HASH: + // return (crc32(shift) >> 16) & 0x7fff; + CRC32 crc32 = new CRC32(); + crc32.update(ByteUtils.getBytes(k)); + rv = crc32.getValue() >> 16 & 0x7fff; + break; + case FNV1_64_HASH: { + // Thanks to pierre@demartines.com for the pointer + rv = FNV_64_INIT; + int len = k.length(); + for (int i = 0; i < len; i++) { + rv *= FNV_64_PRIME; + rv ^= k.charAt(i); + } + } + break; + case FNV1A_64_HASH: { + rv = FNV_64_INIT; + int len = k.length(); + for (int i = 0; i < len; i++) { + rv ^= k.charAt(i); + rv *= FNV_64_PRIME; + } + } + break; + case FNV1_32_HASH: { + rv = FNV_32_INIT; + int len = k.length(); + for (int i = 0; i < len; i++) { + rv *= FNV_32_PRIME; + rv ^= k.charAt(i); + } + } + break; + case FNV1A_32_HASH: { + rv = FNV_32_INIT; + int len = k.length(); + for (int i = 0; i < len; i++) { + rv ^= k.charAt(i); + rv *= FNV_32_PRIME; + } + } + break; + case ELECTION_HASH: + case KETAMA_HASH: + byte[] bKey = computeMd5(k); + rv = (long) (bKey[3] & 0xFF) << 24 | (long) (bKey[2] & 0xFF) << 16 + | (long) (bKey[1] & 0xFF) << 8 | bKey[0] & 0xFF; + break; + + case MYSQL_HASH: + int nr2 = 4; + for (int i = 0; i < k.length(); i++) { + rv ^= ((rv & 63) + nr2) * k.charAt(i) + (rv << 8); + nr2 += 3; + } + break; + case ELF_HASH: + long x = 0; + for (int i = 0; i < k.length(); i++) { + rv = (rv << 4) + k.charAt(i); + if ((x = rv & 0xF0000000L) != 0) { + rv ^= x >> 24; + rv &= ~x; + } + } + rv = rv & 0x7FFFFFFF; + break; + case RS_HASH: + long b = 378551; + long a = 63689; + for (int i = 0; i < k.length(); i++) { + rv = rv * a + k.charAt(i); + a *= b; + } + rv = rv & 0x7FFFFFFF; + break; + case LUA_HASH: + int step = (k.length() >> 5) + 1; + rv = k.length(); + for (int len = k.length(); len >= step; len -= step) { + rv = rv ^ (rv << 5) + (rv >> 2) + k.charAt(len - 1); + } + break; + case ONE_AT_A_TIME: + try { + int hash = 0; + for (byte bt : k.getBytes("utf-8")) { + hash += (bt & 0xFF); + hash += (hash << 10); + hash ^= (hash >>> 6); + } + hash += (hash << 3); + hash ^= (hash >>> 11); + hash += (hash << 15); + rv = hash; + } catch (UnsupportedEncodingException e) { + throw new IllegalStateException("Hash function error", e); + } + break; + default: + assert false; + } + + return rv & 0xffffffffL; /* Convert to unsigned 32-bits */ + } + + private static ThreadLocal md5Local = new ThreadLocal(); + + /** + * Get the md5 of the given key. + */ + public static byte[] computeMd5(String k) { + MessageDigest md5 = md5Local.get(); + if (md5 == null) { + try { + md5 = MessageDigest.getInstance("MD5"); + md5Local.set(md5); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("MD5 not supported", e); + } + } + md5.reset(); + md5.update(ByteUtils.getBytes(k)); + return md5.digest(); + } + + // public static void main(String[] args) { + // HashAlgorithm alg=HashAlgorithm.CRC32_HASH; + // long h=0; + // long start=System.currentTimeMillis(); + // for(int i=0;i<100000;i++) + // h=alg.hash("MYSQL_HASH"); + // System.out.println(System.currentTimeMillis()-start); + // } +} diff --git a/src/main/java/net/rubyeye/xmemcached/KeyIterator.java b/src/main/java/net/rubyeye/xmemcached/KeyIterator.java index 43e27a396..5bf7b0ccf 100644 --- a/src/main/java/net/rubyeye/xmemcached/KeyIterator.java +++ b/src/main/java/net/rubyeye/xmemcached/KeyIterator.java @@ -2,65 +2,60 @@ import java.net.InetSocketAddress; import java.util.concurrent.TimeoutException; - import net.rubyeye.xmemcached.exception.MemcachedException; /** - * Key Iterator for memcached,use 'stats items' and 'stats cachedump' to iterate - * all keys,it is inefficient and not thread-safe.The 'stats cachedump" has - * length limitation,then iterator could not visit all keys if you have many - * keys.
+ * Key Iterator for memcached,use 'stats items' and 'stats cachedump' to iterate all keys,it is + * inefficient and not thread-safe.The 'stats cachedump" has length limitation,then iterator could + * not visit all keys if you have many keys.
*

- * Note: memcached 1.6.x will remove cachedump stats,so this - * feature will be invalid in memcached 1.6.x + * Note: memcached 1.6.x will remove cachedump stats,so this feature will be + * invalid in memcached 1.6.x *

* - * @deprecated memcached 1.6.x will remove cachedump stats command,so this - * feature will be removed in the future + * @deprecated memcached 1.6.x will remove cachedump stats command,so this feature will be removed + * in the future * * @author dennis * */ @Deprecated public interface KeyIterator { - /** - * Get next key,if iterator has reached the end,throw - * ArrayIndexOutOfBoundsException - * - * @return - * @throws ArrayIndexOutOfBoundsException - * ,MemcachedException,TimeoutException,InterruptedException - * - */ - public String next() - throws MemcachedException, TimeoutException, InterruptedException; - - /** - * Check if the iterator has more keys. - * - * @return - */ - public boolean hasNext(); - - /** - * Close this iterator when you don't need it any more.It is not mandatory - * to call this method, but you might want to invoke this method for maximum - * performance. - */ - public void close(); - - /** - * Get current iterator's memcached server address - * - * @return - */ - public InetSocketAddress getServerAddress(); - - /** - * Set operation timeout,default is 1000 MILLISECONDS. - * - * @param opTimeout - */ - public void setOpTimeout(long opTimeout); + /** + * Get next key,if iterator has reached the end,throw ArrayIndexOutOfBoundsException + * + * @return + * @throws ArrayIndexOutOfBoundsException + * ,MemcachedException,TimeoutException,InterruptedException + * + */ + public String next() throws MemcachedException, TimeoutException, InterruptedException; + + /** + * Check if the iterator has more keys. + * + * @return + */ + public boolean hasNext(); + + /** + * Close this iterator when you don't need it any more.It is not mandatory to call this method, + * but you might want to invoke this method for maximum performance. + */ + public void close(); + + /** + * Get current iterator's memcached server address + * + * @return + */ + public InetSocketAddress getServerAddress(); + + /** + * Set operation timeout,default is 1000 MILLISECONDS. + * + * @param opTimeout + */ + public void setOpTimeout(long opTimeout); } diff --git a/src/main/java/net/rubyeye/xmemcached/KeyProvider.java b/src/main/java/net/rubyeye/xmemcached/KeyProvider.java index 7426902c2..d78b9d378 100644 --- a/src/main/java/net/rubyeye/xmemcached/KeyProvider.java +++ b/src/main/java/net/rubyeye/xmemcached/KeyProvider.java @@ -1,17 +1,17 @@ -package net.rubyeye.xmemcached; - -/** - * Key provider to pre-process keys before sending to memcached. - * - * @author dennis - * @since 1.3.8 - */ -public interface KeyProvider { - /** - * Processes key and returns a new key. - * - * @param key - * @return - */ - public String process(String key); -} +package net.rubyeye.xmemcached; + +/** + * Key provider to pre-process keys before sending to memcached. + * + * @author dennis + * @since 1.3.8 + */ +public interface KeyProvider { + /** + * Processes key and returns a new key. + * + * @param key + * @return + */ + public String process(String key); +} diff --git a/src/main/java/net/rubyeye/xmemcached/MemcachedClient.java b/src/main/java/net/rubyeye/xmemcached/MemcachedClient.java index 38d40a54b..71dd32fb9 100644 --- a/src/main/java/net/rubyeye/xmemcached/MemcachedClient.java +++ b/src/main/java/net/rubyeye/xmemcached/MemcachedClient.java @@ -7,7 +7,6 @@ import java.util.Map; import java.util.Queue; import java.util.concurrent.TimeoutException; - import net.rubyeye.xmemcached.auth.AuthInfo; import net.rubyeye.xmemcached.buffer.BufferAllocator; import net.rubyeye.xmemcached.exception.MemcachedException; @@ -24,1887 +23,1718 @@ */ public interface MemcachedClient { - /** - * Default thread number for reading nio's receive buffer and dispatch - * commands.Recommend users to set it equal or less to the memcached - * server's number on linux platform,keep default on windows.Default is 0. - */ - public static final int DEFAULT_READ_THREAD_COUNT = 0; - - /** - * Default TCP keeplive option,which is true - */ - public static final boolean DEFAULT_TCP_KEEPLIVE = true; - /** - * Default connect timeout,1 minutes - */ - public static final int DEFAULT_CONNECT_TIMEOUT = 60000; - /** - * Default socket's send buffer size,8k - */ - public static final int DEFAULT_TCP_SEND_BUFF_SIZE = 32 * 1024; - /** - * Disable nagle algorithm by default - * - */ - public static final boolean DEFAULT_TCP_NO_DELAY = true; - /** - * Default session read buffer size,16k - */ - public static final int DEFAULT_SESSION_READ_BUFF_SIZE = 128 * 1024; - /** - * Default socket's receive buffer size,16k - */ - public static final int DEFAULT_TCP_RECV_BUFF_SIZE = 64 * 1024; - /** - * Default operation timeout,if the operation is not returned in 5 - * second,throw TimeoutException. - */ - public static final long DEFAULT_OP_TIMEOUT = 5000L; - /** - * With java nio,there is only one connection to a memcached.In a high - * concurrent enviroment,you may want to pool memcached clients.But a - * xmemcached client has to start a reactor thread and some thread pools,if - * you create too many clients,the cost is very large. Xmemcached supports - * connection pool instreadof client pool.you can create more connections to - * one or more memcached servers,and these connections share the same - * reactor and thread pools,it will reduce the cost of system.Default pool - * size is 1. - */ - public static final int DEFAULT_CONNECTION_POOL_SIZE = 1; - - /** - * Default session idle timeout,if session is idle,xmemcached will do a - * heartbeat action to check if connection is alive. - */ - public static final int DEFAULT_SESSION_IDLE_TIMEOUT = 5000; - - /** - * Default heal session interval in milliseconds. - */ - public static final long DEFAULT_HEAL_SESSION_INTERVAL = 2000; - - int MAX_QUEUED_NOPS = 40000; - int DYNAMIC_MAX_QUEUED_NOPS = (int) (MAX_QUEUED_NOPS - * (Runtime.getRuntime().maxMemory() / 1024.0 / 1024.0 / 1024.0)); - - /** - * Default max queued noreply operations number.It is calcuated dynamically - * based on your jvm maximum memory. - * - * @since 1.3.8 - */ - public static final int DEFAULT_MAX_QUEUED_NOPS = DYNAMIC_MAX_QUEUED_NOPS > MAX_QUEUED_NOPS - ? MAX_QUEUED_NOPS - : DYNAMIC_MAX_QUEUED_NOPS; - - /** - * Maximum number of timeout exception for close connection. - * - * @since 1.4.0 - */ - public static final int DEFAULT_MAX_TIMEOUTEXCEPTION_THRESHOLD = 1000; - - /** - * Set the merge factor,this factor determins how many 'get' commands would - * be merge to one multi-get command.default is 150 - * - * @param mergeFactor - */ - public void setMergeFactor(final int mergeFactor); - - /** - * Get the connect timeout - * - */ - public long getConnectTimeout(); - - /** - * Set the connect timeout,default is 1 minutes - * - * @param connectTimeout - */ - public void setConnectTimeout(long connectTimeout); - - /** - * return the session manager - * - * @return - */ - public Connector getConnector(); - - /** - * Enable/Disable merge many get commands to one multi-get command.true is - * to enable it,false is to disable it.Default is true.Recommend users to - * enable it. - * - * @param optimizeGet - */ - public void setOptimizeGet(final boolean optimizeGet); - - /** - * Enable/Disable merge many command's buffers to one big buffer fit - * socket's send buffer size.Default is true.Recommend true. - * - * @param optimizeMergeBuffer - */ - public void setOptimizeMergeBuffer(final boolean optimizeMergeBuffer); - - /** - * @return - */ - public boolean isShutdown(); - - /** - * Aadd a memcached server,the thread call this method will be blocked until - * the connecting operations completed(success or fail) - * - * @param server - * host string - * @param port - * port number - */ - public void addServer(final String server, final int port) - throws IOException; - - /** - * Add a memcached server,the thread call this method will be blocked until - * the connecting operations completed(success or fail) - * - * @param inetSocketAddress - * memcached server's socket address - */ - public void addServer(final InetSocketAddress inetSocketAddress) - throws IOException; - - /** - * Add many memcached servers.You can call this method through JMX or - * program - * - * @param host - * String like [host1]:[port1] [host2]:[port2] ... - */ - public void addServer(String hostList) throws IOException; - - /** - * Get current server list.You can call this method through JMX or program - */ - public List getServersDescription(); - - /** - * Remove many memcached server - * - * @param host - * String like [host1]:[port1] [host2]:[port2] ... - */ - public void removeServer(String hostList); - - /** - * Set the nio's ByteBuffer Allocator,use SimpleBufferAllocator by default. - * - * - * @param bufferAllocator - * @return - */ - @Deprecated - public void setBufferAllocator(final BufferAllocator bufferAllocator); - - /** - * Get value by key - * - * @param - * @param key - * Key - * @param timeout - * Operation timeout,if the method is not returned in this - * time,throw TimeoutException - * @param transcoder - * The value's transcoder - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public T get(final String key, final long timeout, - final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException; - - public T get(final String key, final long timeout) - throws TimeoutException, InterruptedException, MemcachedException; - - public T get(final String key, final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException; - - public T get(final String key) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Just like get,But it return a GetsResponse,include cas value for cas - * update. - * - * @param - * @param key - * key - * @param timeout - * operation timeout - * @param transcoder - * - * @return GetsResponse - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public GetsResponse gets(final String key, final long timeout, - final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * @see #gets(String, long, Transcoder) - * @param - * @param key - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public GetsResponse gets(final String key) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * @see #gets(String, long, Transcoder) - * @param - * @param key - * @param timeout - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public GetsResponse gets(final String key, final long timeout) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * @see #gets(String, long, Transcoder) - * @param - * @param key - * @param transcoder - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - @SuppressWarnings("unchecked") - public GetsResponse gets(final String key, - final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Bulk get items - * - * @param - * @param keyCollections - * key collection - * @param opTimeout - * opTimeout - * @param transcoder - * Value transcoder - * @return Exists items map - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public Map get(final Collection keyCollections, - final long opTimeout, final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * @see #get(Collection, long, Transcoder) - * @param - * @param keyCollections - * @param transcoder - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public Map get(final Collection keyCollections, - final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * @see #get(Collection, long, Transcoder) - * @param - * @param keyCollections - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public Map get(final Collection keyCollections) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * @see #get(Collection, long, Transcoder) - * @param - * @param keyCollections - * @param timeout - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public Map get(final Collection keyCollections, - final long timeout) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Bulk gets items - * - * @param - * @param keyCollections - * key collection - * @param opTime - * Operation timeout - * @param transcoder - * Value transcoder - * @return Exists GetsResponse map - * @see net.rubyeye.xmemcached.GetsResponse - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public Map> gets( - final Collection keyCollections, final long opTime, - final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * @see #gets(Collection, long, Transcoder) - * @param - * @param keyCollections - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public Map> gets( - final Collection keyCollections) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * @see #gets(Collection, long, Transcoder) - * @param - * @param keyCollections - * @param timeout - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public Map> gets( - final Collection keyCollections, final long timeout) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * @see #gets(Collection, long, Transcoder) - * @param - * @param keyCollections - * @param transcoder - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public Map> gets( - final Collection keyCollections, - final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Store key-value item to memcached - * - * @param - * @param key - * stored key - * @param exp - * An expiration time, in seconds. Can be up to 30 days. After 30 - * days, is treated as a unix timestamp of an exact date. - * @param value - * stored data - * @param transcoder - * transocder - * @param timeout - * operation timeout,in milliseconds - * @return boolean result - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public boolean set(final String key, final int exp, final T value, - final Transcoder transcoder, final long timeout) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * @see #set(String, int, Object, Transcoder, long) - */ - public boolean set(final String key, final int exp, final Object value) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * @see #set(String, int, Object, Transcoder, long) - */ - public boolean set(final String key, final int exp, final Object value, - final long timeout) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * @see #set(String, int, Object, Transcoder, long) - */ - public boolean set(final String key, final int exp, final T value, - final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Store key-value item to memcached,doesn't wait for reply - * - * @param - * @param key - * stored key - * @param exp - * An expiration time, in seconds. Can be up to 30 days. After 30 - * days, is treated as a unix timestamp of an exact date. - * @param value - * stored data - * @param transcoder - * transocder - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public void setWithNoReply(final String key, final int exp, - final Object value) throws InterruptedException, MemcachedException; - - /** - * @see #setWithNoReply(String, int, Object, Transcoder) - * @param - * @param key - * @param exp - * @param value - * @param transcoder - * @throws InterruptedException - * @throws MemcachedException - */ - public void setWithNoReply(final String key, final int exp, - final T value, final Transcoder transcoder) - throws InterruptedException, MemcachedException; - - /** - * Add key-value item to memcached, success only when the key is not exists - * in memcached. - * - * @param - * @param key - * @param exp - * An expiration time, in seconds. Can be up to 30 days. After 30 - * days, is treated as a unix timestamp of an exact date. - * @param value - * @param transcoder - * @param timeout - * @return boolean result - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public boolean add(final String key, final int exp, final T value, - final Transcoder transcoder, final long timeout) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * @see #add(String, int, Object, Transcoder, long) - * @param key - * @param exp - * @param value - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public boolean add(final String key, final int exp, final Object value) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * @see #add(String, int, Object, Transcoder, long) - * @param key - * @param exp - * @param value - * @param timeout - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public boolean add(final String key, final int exp, final Object value, - final long timeout) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * @see #add(String, int, Object, Transcoder, long) - * - * @param - * @param key - * @param exp - * @param value - * @param transcoder - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public boolean add(final String key, final int exp, final T value, - final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Add key-value item to memcached, success only when the key is not exists - * in memcached.This method doesn't wait for reply. - * - * @param - * @param key - * @param exp - * An expiration time, in seconds. Can be up to 30 days. After 30 - * days, is treated as a unix timestamp of an exact date. - * @param value - * @param transcoder - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - - public void addWithNoReply(final String key, final int exp, - final Object value) throws InterruptedException, MemcachedException; - - /** - * @see #addWithNoReply(String, int, Object, Transcoder) - * @param - * @param key - * @param exp - * @param value - * @param transcoder - * @throws InterruptedException - * @throws MemcachedException - */ - public void addWithNoReply(final String key, final int exp, - final T value, final Transcoder transcoder) - throws InterruptedException, MemcachedException; - - /** - * Replace the key's data item in memcached,success only when the key's data - * item is exists in memcached.This method will wait for reply from server. - * - * @param - * @param key - * @param exp - * An expiration time, in seconds. Can be up to 30 days. After 30 - * days, is treated as a unix timestamp of an exact date. - * @param value - * @param transcoder - * @param timeout - * @return boolean result - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public boolean replace(final String key, final int exp, final T value, - final Transcoder transcoder, final long timeout) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * @see #replace(String, int, Object, Transcoder, long) - * @param key - * @param exp - * @param value - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public boolean replace(final String key, final int exp, final Object value) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * @see #replace(String, int, Object, Transcoder, long) - * @param key - * @param exp - * @param value - * @param timeout - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public boolean replace(final String key, final int exp, final Object value, - final long timeout) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * @see #replace(String, int, Object, Transcoder, long) - * @param - * @param key - * @param exp - * @param value - * @param transcoder - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public boolean replace(final String key, final int exp, final T value, - final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Replace the key's data item in memcached,success only when the key's data - * item is exists in memcached.This method doesn't wait for reply from - * server. - * - * @param - * @param key - * @param exp - * An expiration time, in seconds. Can be up to 30 days. After 30 - * days, is treated as a unix timestamp of an exact date. - * @param value - * @param transcoder - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public void replaceWithNoReply(final String key, final int exp, - final Object value) throws InterruptedException, MemcachedException; - - /** - * @see #replaceWithNoReply(String, int, Object, Transcoder) - * @param - * @param key - * @param exp - * @param value - * @param transcoder - * @throws InterruptedException - * @throws MemcachedException - */ - public void replaceWithNoReply(final String key, final int exp, - final T value, final Transcoder transcoder) - throws InterruptedException, MemcachedException; - - /** - * @see #append(String, Object, long) - * @param key - * @param value - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public boolean append(final String key, final Object value) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Append value to key's data item,this method will wait for reply - * - * @param key - * @param value - * @param timeout - * @return boolean result - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public boolean append(final String key, final Object value, - final long timeout) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Append value to key's data item,this method doesn't wait for reply. - * - * @param key - * @param value - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public void appendWithNoReply(final String key, final Object value) - throws InterruptedException, MemcachedException; - - /** - * @see #prepend(String, Object, long) - * @param key - * @param value - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public boolean prepend(final String key, final Object value) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Prepend value to key's data item in memcached.This method doesn't wait - * for reply. - * - * @param key - * @param value - * @return boolean result - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public boolean prepend(final String key, final Object value, - final long timeout) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Prepend value to key's data item in memcached.This method doesn't wait - * for reply. - * - * @param key - * @param value - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public void prependWithNoReply(final String key, final Object value) - throws InterruptedException, MemcachedException; - - /** - * @see #cas(String, int, Object, Transcoder, long, long) - * @param key - * @param exp - * @param value - * @param cas - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public boolean cas(final String key, final int exp, final Object value, - final long cas) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Cas is a check and set operation which means "store this data but only if - * no one else has updated since I last fetched it." - * - * @param - * @param key - * @param exp - * An expiration time, in seconds. Can be up to 30 days. After 30 - * days, is treated as a unix timestamp of an exact date. - * @param value - * @param transcoder - * @param timeout - * @param cas - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public boolean cas(final String key, final int exp, final T value, - final Transcoder transcoder, final long timeout, final long cas) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * @see #cas(String, int, Object, Transcoder, long, long) - * @param key - * @param exp - * @param value - * @param timeout - * @param cas - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public boolean cas(final String key, final int exp, final Object value, - final long timeout, final long cas) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * @see #cas(String, int, Object, Transcoder, long, long) - * @param - * @param key - * @param exp - * @param value - * @param transcoder - * @param cas - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public boolean cas(final String key, final int exp, final T value, - final Transcoder transcoder, final long cas) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Cas is a check and set operation which means "store this data but only if - * no one else has updated since I last fetched it." - * - * @param - * @param key - * @param exp - * An expiration time, in seconds. Can be up to 30 days. After 30 - * days, is treated as a unix timestamp of an exact date. - * @param operation - * CASOperation - * @param transcoder - * object transcoder - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public boolean cas(final String key, final int exp, - final CASOperation operation, final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * cas is a check and set operation which means "store this data but only if - * no one else has updated since I last fetched it." - * - * @param - * @param key - * @param exp - * An expiration time, in seconds. Can be up to 30 days. After 30 - * days, is treated as a unix timestamp of an exact date. - * @param getsReponse - * gets method's result - * @param operation - * CASOperation - * @param transcoder - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public boolean cas(final String key, final int exp, - GetsResponse getsReponse, final CASOperation operation, - final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * @see #cas(String, int, GetsResponse, CASOperation, Transcoder) - * @param - * @param key - * @param exp - * @param getsReponse - * @param operation - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public boolean cas(final String key, final int exp, - GetsResponse getsReponse, final CASOperation operation) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * @see #cas(String, int, GetsResponse, CASOperation, Transcoder) - * @param - * @param key - * @param getsResponse - * @param operation - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public boolean cas(final String key, GetsResponse getsResponse, - final CASOperation operation) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * @see #cas(String, int, GetsResponse, CASOperation, Transcoder) - * @param - * @param key - * @param exp - * @param operation - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public boolean cas(final String key, final int exp, - final CASOperation operation) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * @see #cas(String, int, GetsResponse, CASOperation, Transcoder) - * @param - * @param key - * @param operation - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public boolean cas(final String key, final CASOperation operation) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * - * @param - * @param key - * @param getsResponse - * @param operation - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public void casWithNoReply(final String key, - GetsResponse getsResponse, final CASOperation operation) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * cas noreply - * - * @param - * @param key - * @param exp - * @param getsReponse - * @param operation - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public void casWithNoReply(final String key, final int exp, - GetsResponse getsReponse, final CASOperation operation) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * @see #casWithNoReply(String, int, GetsResponse, CASOperation) - * @param - * @param key - * @param exp - * @param operation - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public void casWithNoReply(final String key, final int exp, - final CASOperation operation) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * @see #casWithNoReply(String, int, GetsResponse, CASOperation) - * @param - * @param key - * @param operation - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public void casWithNoReply(final String key, - final CASOperation operation) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Delete key's data item from memcached.It it is not exists,return - * false.
- * time is the amount of time in seconds (or Unix time until
- * which) the client wishes the server to refuse "add" and "replace"
- * commands with this key. For this amount of item, the item is put into - * a
- * delete queue, which means that it won't possible to retrieve it by - * the
- * "get" command, but "add" and "replace" command with this key will - * also
- * fail (the "set" command will succeed, however). After the time - * passes,
- * the item is finally deleted from server memory.
- * Note: This method is deprecated,because memcached 1.4.0 remove - * the optional argument "time".You can still use this method on old - * version,but is not recommended. - * - * @param key - * @param time - * @throws InterruptedException - * @throws MemcachedException - */ - @Deprecated - public boolean delete(final String key, final int time) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Delete key's date item from memcached - * - * @param key - * @param opTimeout - * Operation timeout - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - * @since 1.3.2 - */ - public boolean delete(final String key, long opTimeout) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Delete key's date item from memcached only if its cas value is the same - * as what was read. - * - * @param key - * @cas cas on delete to make sure the key is deleted only if its value is - * same as what was read. - * @param opTimeout - * Operation timeout - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - * @since 1.3.2 - */ - public boolean delete(final String key, long cas, long opTimeout) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Set a new expiration time for an existing item - * - * @param key - * item's key - * @param exp - * New expiration time, in seconds. Can be up to 30 days. After - * 30 days, is treated as a unix timestamp of an exact date. - * @param opTimeout - * operation timeout - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public boolean touch(final String key, int exp, long opTimeout) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Set a new expiration time for an existing item,using default opTimeout - * second. - * - * @param key - * item's key - * @param exp - * New expiration time, in seconds. Can be up to 30 days. After - * 30 days, is treated as a unix timestamp of an exact date. - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public boolean touch(final String key, int exp) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Get item and set a new expiration time for it - * - * @param - * @param key - * item's key - * @param newExp - * New expiration time, in seconds. Can be up to 30 days. After - * 30 days, is treated as a unix timestamp of an exact date. - * @param opTimeout - * operation timeout - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public T getAndTouch(final String key, int newExp, long opTimeout) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Get item and set a new expiration time for it,using default opTimeout - * - * @param - * @param key - * @param newExp - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public T getAndTouch(final String key, int newExp) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Bulk get items and touch them - * - * @param - * @param keyExpMap - * A map,key is item's key,and value is a new expiration time for - * the item. - * @param opTimeout - * operation timeout - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - // public Map getAndTouch(Map keyExpMap, - // long opTimeout) throws TimeoutException, InterruptedException, - // MemcachedException; - - /** - * Bulk get items and touch them,using default opTimeout - * - * @see #getAndTouch(Map, long) - * @param - * @param keyExpMap - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - // public Map getAndTouch(Map keyExpMap) - // throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Get all connected memcached servers's version. - * - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public Map getVersions() - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * "incr" are used to change data for some item in-place, incrementing it. - * The data for the item is treated as decimal representation of a 64-bit - * unsigned integer. If the current data value does not conform to such a - * representation, the commands behave as if the value were 0. Also, the - * item must already exist for incr to work; these commands won't pretend - * that a non-existent key exists with value 0; instead, it will fail.This - * method doesn't wait for reply. - * - * @return the new value of the item's data, after the increment operation - * was carried out. - * @param key - * @param num - * @throws InterruptedException - * @throws MemcachedException - */ - public long incr(final String key, final long delta) - throws TimeoutException, InterruptedException, MemcachedException; - - public long incr(final String key, final long delta, final long initValue) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * "incr" are used to change data for some item in-place, incrementing it. - * The data for the item is treated as decimal representation of a 64-bit - * unsigned integer. If the current data value does not conform to such a - * representation, the commands behave as if the value were 0. Also, the - * item must already exist for incr to work; these commands won't pretend - * that a non-existent key exists with value 0; instead, it will fail.This - * method doesn't wait for reply. - * - * @param key - * key - * @param num - * increment - * @param initValue - * initValue if the data is not exists. - * @param timeout - * operation timeout - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public long incr(final String key, final long delta, final long initValue, - long timeout) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * "decr" are used to change data for some item in-place, decrementing it. - * The data for the item is treated as decimal representation of a 64-bit - * unsigned integer. If the current data value does not conform to such a - * representation, the commands behave as if the value were 0. Also, the - * item must already exist for decr to work; these commands won't pretend - * that a non-existent key exists with value 0; instead, it will fail.This - * method doesn't wait for reply. - * - * @return the new value of the item's data, after the decrement operation - * was carried out. - * @param key - * @param num - * @throws InterruptedException - * @throws MemcachedException - */ - public long decr(final String key, final long delta) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * @see decr - * @param key - * @param num - * @param initValue - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public long decr(final String key, final long delta, long initValue) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * "decr" are used to change data for some item in-place, decrementing it. - * The data for the item is treated as decimal representation of a 64-bit - * unsigned integer. If the current data value does not conform to such a - * representation, the commands behave as if the value were 0. Also, the - * item must already exist for decr to work; these commands won't pretend - * that a non-existent key exists with value 0; instead, it will fail.This - * method doesn't wait for reply. - * - * @param key - * The key - * @param num - * The increment - * @param initValue - * The initial value if the data is not exists. - * @param timeout - * Operation timeout - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public long decr(final String key, final long delta, long initValue, - long timeout) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Make All connected memcached's data item invalid - * - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public void flushAll() - throws TimeoutException, InterruptedException, MemcachedException; - - public void flushAllWithNoReply() - throws InterruptedException, MemcachedException; - - /** - * Make All connected memcached's data item invalid - * - * @param timeout - * operation timeout - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public void flushAll(long timeout) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Invalidate all existing items immediately - * - * @param address - * Target memcached server - * @param timeout - * operation timeout - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public void flushAll(InetSocketAddress address) - throws MemcachedException, InterruptedException, TimeoutException; - - public void flushAllWithNoReply(InetSocketAddress address) - throws MemcachedException, InterruptedException; - - public void flushAll(InetSocketAddress address, long timeout) - throws MemcachedException, InterruptedException, TimeoutException; - - /** - * This method is deprecated,please use flushAll(InetSocketAddress) instead. - * - * @deprecated - * @param host - * - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - @Deprecated - public void flushAll(String host) - throws TimeoutException, InterruptedException, MemcachedException; - - public Map stats(InetSocketAddress address) - throws MemcachedException, InterruptedException, TimeoutException; - - /** - * �ョ��瑰������emcached server缁��淇℃� - * - * @param address - * ����板� - * @param timeout - * ���瓒�� - * @return - * @throws MemcachedException - * @throws InterruptedException - * @throws TimeoutException - */ - public Map stats(InetSocketAddress address, long timeout) - throws MemcachedException, InterruptedException, TimeoutException; - - /** - * Get stats from all memcached servers - * - * @param timeout - * @return server->item->value map - * @throws MemcachedException - * @throws InterruptedException - * @throws TimeoutException - */ - public Map> getStats(long timeout) - throws MemcachedException, InterruptedException, TimeoutException; - - public Map> getStats() - throws MemcachedException, InterruptedException, TimeoutException; - - /** - * Get special item stats. "stats items" for example - * - * @param item - * @return - */ - public Map> getStatsByItem( - String itemName) - throws MemcachedException, InterruptedException, TimeoutException;; - - public void shutdown() throws IOException; - - public boolean delete(final String key) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * return default transcoder,default is SerializingTranscoder - * - * @return - */ - @SuppressWarnings("unchecked") - public Transcoder getTranscoder(); - - /** - * set transcoder - * - * @param transcoder - */ - @SuppressWarnings("unchecked") - public void setTranscoder(final Transcoder transcoder); - - public Map> getStatsByItem( - String itemName, long timeout) - throws MemcachedException, InterruptedException, TimeoutException; - - /** - * get operation timeout setting - * - * @return - */ - public long getOpTimeout(); - - /** - * set operation timeout,default is one second. - * - * @param opTimeout - */ - public void setOpTimeout(long opTimeout); - - public Map getVersions(long timeout) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Returns available memcached servers list.This method is drepcated,please - * use getAvailableServers instead. - * - * @see #getAvailableServers() - * @return - */ - @Deprecated - public Collection getAvaliableServers(); - - /** - * Returns available memcached servers list. - * - * @return A available server collection - */ - public Collection getAvailableServers(); - - /** - * add a memcached server to MemcachedClient - * - * @param server - * @param port - * @param weight - * @throws IOException - */ - public void addServer(final String server, final int port, int weight) - throws IOException; - - public void addServer(final InetSocketAddress inetSocketAddress, int weight) - throws IOException; - - /** - * Delete key's data item from memcached.This method doesn't wait for reply. - * This method does not work on memcached 1.3 or later version.See i s s u e 3
- * Note: This method is deprecated,because memcached 1.4.0 remove - * the optional argument "time".You can still use this method on old - * version,but is not recommended. - * - * @param key - * @param time - * @throws InterruptedException - * @throws MemcachedException - */ - @Deprecated - public void deleteWithNoReply(final String key, final int time) - throws InterruptedException, MemcachedException; - - public void deleteWithNoReply(final String key) - throws InterruptedException, MemcachedException; - - /** - * "incr" are used to change data for some item in-place, incrementing it. - * The data for the item is treated as decimal representation of a 64-bit - * unsigned integer. If the current data value does not conform to such a - * representation, the commands behave as if the value were 0. Also, the - * item must already exist for incr to work; these commands won't pretend - * that a non-existent key exists with value 0; instead, it will fail.This - * method doesn't wait for reply. - * - * @param key - * @param num - * @throws InterruptedException - * @throws MemcachedException - */ - public void incrWithNoReply(final String key, final long delta) - throws InterruptedException, MemcachedException; - - /** - * "decr" are used to change data for some item in-place, decrementing it. - * The data for the item is treated as decimal representation of a 64-bit - * unsigned integer. If the current data value does not conform to such a - * representation, the commands behave as if the value were 0. Also, the - * item must already exist for decr to work; these commands won't pretend - * that a non-existent key exists with value 0; instead, it will fail.This - * method doesn't wait for reply. - * - * @param key - * @param num - * @throws InterruptedException - * @throws MemcachedException - */ - public void decrWithNoReply(final String key, final long delta) - throws InterruptedException, MemcachedException; - - /** - * Set the verbosity level of the memcached's logging output.This method - * will wait for reply. - * - * @param address - * @param level - * logging level - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public void setLoggingLevelVerbosity(InetSocketAddress address, int level) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Set the verbosity level of the memcached's logging output.This method - * doesn't wait for reply from server - * - * @param address - * memcached server address - * @param level - * logging level - * @throws InterruptedException - * @throws MemcachedException - */ - public void setLoggingLevelVerbosityWithNoReply(InetSocketAddress address, - int level) throws InterruptedException, MemcachedException; - - /** - * Add a memcached client listener - * - * @param listener - */ - public void addStateListener(MemcachedClientStateListener listener); - - /** - * Remove a memcached client listener - * - * @param listener - */ - public void removeStateListener(MemcachedClientStateListener listener); - - /** - * Get all current state listeners - * - * @return - */ - public Collection getStateListeners(); - - public void flushAllWithNoReply(int exptime) - throws InterruptedException, MemcachedException; - - public void flushAll(int exptime, long timeout) - throws TimeoutException, InterruptedException, MemcachedException; - - public void flushAllWithNoReply(InetSocketAddress address, int exptime) - throws MemcachedException, InterruptedException; - - public void flushAll(InetSocketAddress address, long timeout, int exptime) - throws MemcachedException, InterruptedException, TimeoutException; - - /** - * If the memcached dump or network error cause connection closed,xmemcached - * would try to heal the connection.The interval between reconnections is 2 - * seconds by default. You can change that value by this method. - * - * @param healConnectionInterval - * MILLISECONDS - */ - public void setHealSessionInterval(long healConnectionInterval); - - /** - * If the memcached dump or network error cause connection closed,xmemcached - * would try to heal the connection.You can disable this behaviour by using - * this method:
- * client.setEnableHealSession(false);
- * The default value is true. - * - * @param enableHealSession - * @since 1.3.9 - */ - public void setEnableHealSession(boolean enableHealSession); - - /** - * Return the default heal session interval in milliseconds - * - * @return - */ - public long getHealSessionInterval(); - - public Protocol getProtocol(); - - /** - * Store all primitive type as string,defualt is false. - */ - public void setPrimitiveAsString(boolean primitiveAsString); - - /** - * In a high concurrent enviroment,you may want to pool memcached - * clients.But a xmemcached client has to start a reactor thread and some - * thread pools,if you create too many clients,the cost is very large. - * Xmemcached supports connection pool instreadof client pool.you can create - * more connections to one or more memcached servers,and these connections - * share the same reactor and thread pools,it will reduce the cost of - * system. - * - * @param poolSize - * pool size,default is one,every memcached has only one - * connection. - */ - public void setConnectionPoolSize(int poolSize); - - /** - * Whether to enable heart beat - * - * @param enableHeartBeat - * if true,then enable heartbeat,true by default - */ - public void setEnableHeartBeat(boolean enableHeartBeat); - - /** - * Enables/disables sanitizing keys by URLEncoding. - * - * @param sanitizeKey - * if true, then URLEncode all keys - */ - public void setSanitizeKeys(boolean sanitizeKey); - - public boolean isSanitizeKeys(); - - /** - * Get counter for key,and if the key's value is not set,then set it with 0. - * - * @param key - * @return - */ - public Counter getCounter(String key); - - /** - * Get counter for key,and if the key's value is not set,then set it with - * initial value. - * - * @param key - * @param initialValue - * @return - */ - public Counter getCounter(String key, long initialValue); - - /** - * Get key iterator for special memcached server.You must known that the - * iterator is a snapshot for memcached all keys,it is not real-time.The - * 'stats cachedump" has length limitation,so iterator could not visit all - * keys if you have many keys.Your application should not be dependent on - * this feature. - * - * @deprecated memcached 1.6.x will remove cachedump stats command,so this - * method will be removed in the future - * @param address - * @return - */ - @Deprecated - public KeyIterator getKeyIterator(InetSocketAddress address) - throws MemcachedException, InterruptedException, TimeoutException; - - /** - * Configure auth info - * - * @param map - * Auth info map,key is memcached server address,and value is the - * auth info for the key. - */ - public void setAuthInfoMap(Map map); - - /** - * return current all auth info - * - * @return Auth info map,key is memcached server address,and value is the - * auth info for the key. - */ - public Map getAuthInfoMap(); - - /** - * "incr" are used to change data for some item in-place, incrementing it. - * The data for the item is treated as decimal representation of a 64-bit - * unsigned integer. If the current data value does not conform to such a - * representation, the commands behave as if the value were 0. Also, the - * item must already exist for incr to work; these commands won't pretend - * that a non-existent key exists with value 0; instead, it will fail.This - * method doesn't wait for reply. - * - * @param key - * @param delta - * @param initValue - * the initial value to be added when value is not found - * @param timeout - * @param exp - * the initial vlaue expire time, in seconds. Can be up to 30 - * days. After 30 days, is treated as a unix timestamp of an - * exact date. - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - long decr(String key, long delta, long initValue, long timeout, int exp) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * "incr" are used to change data for some item in-place, incrementing it. - * The data for the item is treated as decimal representation of a 64-bit - * unsigned integer. If the current data value does not conform to such a - * representation, the commands behave as if the value were 0. Also, the - * item must already exist for incr to work; these commands won't pretend - * that a non-existent key exists with value 0; instead, it will fail.This - * method doesn't wait for reply. - * - * @param key - * key - * @param delta - * increment delta - * @param initValue - * the initial value to be added when value is not found - * @param timeout - * operation timeout - * @param exp - * the initial vlaue expire time, in seconds. Can be up to 30 - * days. After 30 days, is treated as a unix timestamp of an - * exact date. - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - long incr(String key, long delta, long initValue, long timeout, int exp) - throws TimeoutException, InterruptedException, MemcachedException; - - /** - * Return the cache instance name - * - * @return - */ - public String getName(); - - /** - * Set cache instance name - * - * @param name - */ - public void setName(String name); - - /** - * Returns reconnecting task queue,the queue is thread-safe and 'weakly - * consistent',but maybe you should not modify it at all. - * - * @return The reconnecting task queue,if the client has not been - * started,returns null. - */ - public Queue getReconnectRequestQueue(); - - /** - * Configure wheather to set client in failure mode.If set it to true,that - * means you want to configure client in failure mode. Failure mode is that - * when a memcached server is down,it would not taken from the server list - * but marked as unavailable,and then further requests to this server will - * be transformed to standby node if configured or throw an exception until - * it comes back up. - * - * @param failureMode - * true is to configure client in failure mode. - */ - public void setFailureMode(boolean failureMode); - - /** - * Returns if client is in failure mode. - * - * @return - */ - public boolean isFailureMode(); - - /** - * Set a key provider for pre-processing keys before sending them to - * memcached. - * - * @since 1.3.8 - * @param keyProvider - */ - public void setKeyProvider(KeyProvider keyProvider); - - /** - * Returns maximum number of timeout exception for closing connection. - * - * @return - */ - public int getTimeoutExceptionThreshold(); - - /** - * Set maximum number of timeout exception for closing connection.You can - * set it to be a large value to disable this feature. - * - * @see #DEFAULT_MAX_TIMEOUTEXCEPTION_THRESHOLD - * @param timeoutExceptionThreshold - */ - public void setTimeoutExceptionThreshold(int timeoutExceptionThreshold); - - /** - * Invalidate all namespace under the namespace using the default operation - * timeout. - * - * @since 1.4.2 - * @param ns - * the namespace - * @throws MemcachedException - * @throws InterruptedException - * @throws TimeoutException - */ - public abstract void invalidateNamespace(String ns) - throws MemcachedException, InterruptedException, TimeoutException; - - /** - * Invalidate all items under the namespace. - * - * @since 1.4.2 - * @param ns - * the namespace - * @param opTimeout - * operation timeout in milliseconds. - * @throws MemcachedException - * @throws InterruptedException - * @throws TimeoutException - */ - public void invalidateNamespace(String ns, long opTimeout) - throws MemcachedException, InterruptedException, TimeoutException; - - /** - * Remove current namespace set for this memcached client.It must begin with - * {@link #beginWithNamespace(String)} method. - * - * @see #beginWithNamespace(String) - */ - public void endWithNamespace(); - - /** - * set current namespace for following operations with memcached client.It - * must be ended with {@link #endWithNamespace()} method.For example: - * - *
-	 * memcachedClient.beginWithNamespace(userId);
-	 * try {
-	 * 	memcachedClient.set("username", 0, username);
-	 * 	memcachedClient.set("email", 0, email);
-	 * } finally {
-	 * 	memcachedClient.endWithNamespace();
-	 * }
-	 * 
- * - * @see #endWithNamespace() - * @see #withNamespace(String, MemcachedClientCallable) - * @param ns - */ - public void beginWithNamespace(String ns); - - /** - * With the namespae to do something with current memcached client.All - * operations with memcached client done in callable will be under the - * namespace. {@link #beginWithNamespace(String)} and - * {@link #endWithNamespace()} will called around automatically. For - * example: - * - *
-	 *   memcachedClient.withNamespace(userId,new MemcachedClientCallable{
-	 *     public Void call(MemcachedClient client) throws MemcachedException,
-	InterruptedException, TimeoutException{
-	 *      client.set("username",0,username);
-	 *      client.set("email",0,email);
-	 *      return null;
-	 *     }
-	 *   });
-	 *   //invalidate all items under the namespace.
-	 *   memcachedClient.invalidateNamespace(userId);
-	 * 
- * - * @since 1.4.2 - * @param ns - * @param callable - * @see #beginWithNamespace(String) - * @see #endWithNamespace() - * @return - */ - public T withNamespace(String ns, MemcachedClientCallable callable) - throws MemcachedException, InterruptedException, TimeoutException; - -} \ No newline at end of file + /** + * Default thread number for reading nio's receive buffer and dispatch commands.Recommend users to + * set it equal or less to the memcached server's number on linux platform,keep default on + * windows.Default is 0. + */ + public static final int DEFAULT_READ_THREAD_COUNT = 0; + + /** + * Default TCP keeplive option,which is true + */ + public static final boolean DEFAULT_TCP_KEEPLIVE = true; + /** + * Default connect timeout,1 minutes + */ + public static final int DEFAULT_CONNECT_TIMEOUT = 60000; + /** + * Default socket's send buffer size,8k + */ + public static final int DEFAULT_TCP_SEND_BUFF_SIZE = 32 * 1024; + /** + * Disable nagle algorithm by default + * + */ + public static final boolean DEFAULT_TCP_NO_DELAY = true; + /** + * Default session read buffer size,16k + */ + public static final int DEFAULT_SESSION_READ_BUFF_SIZE = 128 * 1024; + /** + * Default socket's receive buffer size,16k + */ + public static final int DEFAULT_TCP_RECV_BUFF_SIZE = 64 * 1024; + /** + * Default operation timeout,if the operation is not returned in 5 second,throw TimeoutException. + */ + public static final long DEFAULT_OP_TIMEOUT = 5000L; + /** + * With java nio,there is only one connection to a memcached.In a high concurrent enviroment,you + * may want to pool memcached clients.But a xmemcached client has to start a reactor thread and + * some thread pools,if you create too many clients,the cost is very large. Xmemcached supports + * connection pool instreadof client pool.you can create more connections to one or more memcached + * servers,and these connections share the same reactor and thread pools,it will reduce the cost + * of system.Default pool size is 1. + */ + public static final int DEFAULT_CONNECTION_POOL_SIZE = 1; + + /** + * Default session idle timeout,if session is idle,xmemcached will do a heartbeat action to check + * if connection is alive. + */ + public static final int DEFAULT_SESSION_IDLE_TIMEOUT = 5000; + + /** + * Default heal session interval in milliseconds. + */ + public static final long DEFAULT_HEAL_SESSION_INTERVAL = 2000; + + int MAX_QUEUED_NOPS = 40000; + int DYNAMIC_MAX_QUEUED_NOPS = + (int) (MAX_QUEUED_NOPS * (Runtime.getRuntime().maxMemory() / 1024.0 / 1024.0 / 1024.0)); + + /** + * Default max queued noreply operations number.It is calcuated dynamically based on your jvm + * maximum memory. + * + * @since 1.3.8 + */ + public static final int DEFAULT_MAX_QUEUED_NOPS = + DYNAMIC_MAX_QUEUED_NOPS > MAX_QUEUED_NOPS ? MAX_QUEUED_NOPS : DYNAMIC_MAX_QUEUED_NOPS; + + /** + * Maximum number of timeout exception for close connection. + * + * @since 1.4.0 + */ + public static final int DEFAULT_MAX_TIMEOUTEXCEPTION_THRESHOLD = 1000; + + /** + * Set the merge factor,this factor determins how many 'get' commands would be merge to one + * multi-get command.default is 150 + * + * @param mergeFactor + */ + public void setMergeFactor(final int mergeFactor); + + /** + * Get the connect timeout + * + */ + public long getConnectTimeout(); + + /** + * Set the connect timeout,default is 1 minutes + * + * @param connectTimeout + */ + public void setConnectTimeout(long connectTimeout); + + /** + * return the session manager + * + * @return + */ + public Connector getConnector(); + + /** + * Enable/Disable merge many get commands to one multi-get command.true is to enable it,false is + * to disable it.Default is true.Recommend users to enable it. + * + * @param optimizeGet + */ + public void setOptimizeGet(final boolean optimizeGet); + + /** + * Enable/Disable merge many command's buffers to one big buffer fit socket's send buffer + * size.Default is true.Recommend true. + * + * @param optimizeMergeBuffer + */ + public void setOptimizeMergeBuffer(final boolean optimizeMergeBuffer); + + /** + * @return + */ + public boolean isShutdown(); + + /** + * Aadd a memcached server,the thread call this method will be blocked until the connecting + * operations completed(success or fail) + * + * @param server host string + * @param port port number + */ + public void addServer(final String server, final int port) throws IOException; + + /** + * Add a memcached server,the thread call this method will be blocked until the connecting + * operations completed(success or fail) + * + * @param inetSocketAddress memcached server's socket address + */ + public void addServer(final InetSocketAddress inetSocketAddress) throws IOException; + + /** + * Add many memcached servers.You can call this method through JMX or program + * + * @param host String like [host1]:[port1] [host2]:[port2] ... + */ + public void addServer(String hostList) throws IOException; + + /** + * Get current server list.You can call this method through JMX or program + */ + public List getServersDescription(); + + /** + * Remove many memcached server + * + * @param host String like [host1]:[port1] [host2]:[port2] ... + */ + public void removeServer(String hostList); + + /** + * Set the nio's ByteBuffer Allocator,use SimpleBufferAllocator by default. + * + * + * @param bufferAllocator + * @return + */ + @Deprecated + public void setBufferAllocator(final BufferAllocator bufferAllocator); + + /** + * Get value by key + * + * @param + * @param key Key + * @param timeout Operation timeout,if the method is not returned in this time,throw + * TimeoutException + * @param transcoder The value's transcoder + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public T get(final String key, final long timeout, final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException; + + public T get(final String key, final long timeout) + throws TimeoutException, InterruptedException, MemcachedException; + + public T get(final String key, final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException; + + public T get(final String key) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Just like get,But it return a GetsResponse,include cas value for cas update. + * + * @param + * @param key key + * @param timeout operation timeout + * @param transcoder + * + * @return GetsResponse + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public GetsResponse gets(final String key, final long timeout, + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * @see #gets(String, long, Transcoder) + * @param + * @param key + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public GetsResponse gets(final String key) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * @see #gets(String, long, Transcoder) + * @param + * @param key + * @param timeout + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public GetsResponse gets(final String key, final long timeout) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * @see #gets(String, long, Transcoder) + * @param + * @param key + * @param transcoder + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + @SuppressWarnings("unchecked") + public GetsResponse gets(final String key, final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Bulk get items + * + * @param + * @param keyCollections key collection + * @param opTimeout opTimeout + * @param transcoder Value transcoder + * @return Exists items map + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public Map get(final Collection keyCollections, final long opTimeout, + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * @see #get(Collection, long, Transcoder) + * @param + * @param keyCollections + * @param transcoder + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public Map get(final Collection keyCollections, + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * @see #get(Collection, long, Transcoder) + * @param + * @param keyCollections + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public Map get(final Collection keyCollections) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * @see #get(Collection, long, Transcoder) + * @param + * @param keyCollections + * @param timeout + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public Map get(final Collection keyCollections, final long timeout) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Bulk gets items + * + * @param + * @param keyCollections key collection + * @param opTime Operation timeout + * @param transcoder Value transcoder + * @return Exists GetsResponse map + * @see net.rubyeye.xmemcached.GetsResponse + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public Map> gets(final Collection keyCollections, + final long opTime, final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * @see #gets(Collection, long, Transcoder) + * @param + * @param keyCollections + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public Map> gets(final Collection keyCollections) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * @see #gets(Collection, long, Transcoder) + * @param + * @param keyCollections + * @param timeout + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public Map> gets(final Collection keyCollections, + final long timeout) throws TimeoutException, InterruptedException, MemcachedException; + + /** + * @see #gets(Collection, long, Transcoder) + * @param + * @param keyCollections + * @param transcoder + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public Map> gets(final Collection keyCollections, + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Store key-value item to memcached + * + * @param + * @param key stored key + * @param exp An expiration time, in seconds. Can be up to 30 days. After 30 days, is treated as a + * unix timestamp of an exact date. + * @param value stored data + * @param transcoder transocder + * @param timeout operation timeout,in milliseconds + * @return boolean result + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public boolean set(final String key, final int exp, final T value, + final Transcoder transcoder, final long timeout) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * @see #set(String, int, Object, Transcoder, long) + */ + public boolean set(final String key, final int exp, final Object value) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * @see #set(String, int, Object, Transcoder, long) + */ + public boolean set(final String key, final int exp, final Object value, final long timeout) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * @see #set(String, int, Object, Transcoder, long) + */ + public boolean set(final String key, final int exp, final T value, + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Store key-value item to memcached,doesn't wait for reply + * + * @param + * @param key stored key + * @param exp An expiration time, in seconds. Can be up to 30 days. After 30 days, is treated as a + * unix timestamp of an exact date. + * @param value stored data + * @param transcoder transocder + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public void setWithNoReply(final String key, final int exp, final Object value) + throws InterruptedException, MemcachedException; + + /** + * @see #setWithNoReply(String, int, Object, Transcoder) + * @param + * @param key + * @param exp + * @param value + * @param transcoder + * @throws InterruptedException + * @throws MemcachedException + */ + public void setWithNoReply(final String key, final int exp, final T value, + final Transcoder transcoder) throws InterruptedException, MemcachedException; + + /** + * Add key-value item to memcached, success only when the key is not exists in memcached. + * + * @param + * @param key + * @param exp An expiration time, in seconds. Can be up to 30 days. After 30 days, is treated as a + * unix timestamp of an exact date. + * @param value + * @param transcoder + * @param timeout + * @return boolean result + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public boolean add(final String key, final int exp, final T value, + final Transcoder transcoder, final long timeout) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * @see #add(String, int, Object, Transcoder, long) + * @param key + * @param exp + * @param value + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public boolean add(final String key, final int exp, final Object value) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * @see #add(String, int, Object, Transcoder, long) + * @param key + * @param exp + * @param value + * @param timeout + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public boolean add(final String key, final int exp, final Object value, final long timeout) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * @see #add(String, int, Object, Transcoder, long) + * + * @param + * @param key + * @param exp + * @param value + * @param transcoder + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public boolean add(final String key, final int exp, final T value, + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Add key-value item to memcached, success only when the key is not exists in memcached.This + * method doesn't wait for reply. + * + * @param + * @param key + * @param exp An expiration time, in seconds. Can be up to 30 days. After 30 days, is treated as a + * unix timestamp of an exact date. + * @param value + * @param transcoder + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + + public void addWithNoReply(final String key, final int exp, final Object value) + throws InterruptedException, MemcachedException; + + /** + * @see #addWithNoReply(String, int, Object, Transcoder) + * @param + * @param key + * @param exp + * @param value + * @param transcoder + * @throws InterruptedException + * @throws MemcachedException + */ + public void addWithNoReply(final String key, final int exp, final T value, + final Transcoder transcoder) throws InterruptedException, MemcachedException; + + /** + * Replace the key's data item in memcached,success only when the key's data item is exists in + * memcached.This method will wait for reply from server. + * + * @param + * @param key + * @param exp An expiration time, in seconds. Can be up to 30 days. After 30 days, is treated as a + * unix timestamp of an exact date. + * @param value + * @param transcoder + * @param timeout + * @return boolean result + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public boolean replace(final String key, final int exp, final T value, + final Transcoder transcoder, final long timeout) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * @see #replace(String, int, Object, Transcoder, long) + * @param key + * @param exp + * @param value + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public boolean replace(final String key, final int exp, final Object value) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * @see #replace(String, int, Object, Transcoder, long) + * @param key + * @param exp + * @param value + * @param timeout + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public boolean replace(final String key, final int exp, final Object value, final long timeout) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * @see #replace(String, int, Object, Transcoder, long) + * @param + * @param key + * @param exp + * @param value + * @param transcoder + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public boolean replace(final String key, final int exp, final T value, + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Replace the key's data item in memcached,success only when the key's data item is exists in + * memcached.This method doesn't wait for reply from server. + * + * @param + * @param key + * @param exp An expiration time, in seconds. Can be up to 30 days. After 30 days, is treated as a + * unix timestamp of an exact date. + * @param value + * @param transcoder + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public void replaceWithNoReply(final String key, final int exp, final Object value) + throws InterruptedException, MemcachedException; + + /** + * @see #replaceWithNoReply(String, int, Object, Transcoder) + * @param + * @param key + * @param exp + * @param value + * @param transcoder + * @throws InterruptedException + * @throws MemcachedException + */ + public void replaceWithNoReply(final String key, final int exp, final T value, + final Transcoder transcoder) throws InterruptedException, MemcachedException; + + /** + * @see #append(String, Object, long) + * @param key + * @param value + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public boolean append(final String key, final Object value) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Append value to key's data item,this method will wait for reply + * + * @param key + * @param value + * @param timeout + * @return boolean result + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public boolean append(final String key, final Object value, final long timeout) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Append value to key's data item,this method doesn't wait for reply. + * + * @param key + * @param value + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public void appendWithNoReply(final String key, final Object value) + throws InterruptedException, MemcachedException; + + /** + * @see #prepend(String, Object, long) + * @param key + * @param value + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public boolean prepend(final String key, final Object value) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Prepend value to key's data item in memcached.This method doesn't wait for reply. + * + * @param key + * @param value + * @return boolean result + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public boolean prepend(final String key, final Object value, final long timeout) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Prepend value to key's data item in memcached.This method doesn't wait for reply. + * + * @param key + * @param value + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public void prependWithNoReply(final String key, final Object value) + throws InterruptedException, MemcachedException; + + /** + * @see #cas(String, int, Object, Transcoder, long, long) + * @param key + * @param exp + * @param value + * @param cas + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public boolean cas(final String key, final int exp, final Object value, final long cas) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Cas is a check and set operation which means "store this data but only if no one else has + * updated since I last fetched it." + * + * @param + * @param key + * @param exp An expiration time, in seconds. Can be up to 30 days. After 30 days, is treated as a + * unix timestamp of an exact date. + * @param value + * @param transcoder + * @param timeout + * @param cas + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public boolean cas(final String key, final int exp, final T value, + final Transcoder transcoder, final long timeout, final long cas) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * @see #cas(String, int, Object, Transcoder, long, long) + * @param key + * @param exp + * @param value + * @param timeout + * @param cas + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public boolean cas(final String key, final int exp, final Object value, final long timeout, + final long cas) throws TimeoutException, InterruptedException, MemcachedException; + + /** + * @see #cas(String, int, Object, Transcoder, long, long) + * @param + * @param key + * @param exp + * @param value + * @param transcoder + * @param cas + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public boolean cas(final String key, final int exp, final T value, + final Transcoder transcoder, final long cas) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Cas is a check and set operation which means "store this data but only if no one else has + * updated since I last fetched it." + * + * @param + * @param key + * @param exp An expiration time, in seconds. Can be up to 30 days. After 30 days, is treated as a + * unix timestamp of an exact date. + * @param operation CASOperation + * @param transcoder object transcoder + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public boolean cas(final String key, final int exp, final CASOperation operation, + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * cas is a check and set operation which means "store this data but only if no one else has + * updated since I last fetched it." + * + * @param + * @param key + * @param exp An expiration time, in seconds. Can be up to 30 days. After 30 days, is treated as a + * unix timestamp of an exact date. + * @param getsReponse gets method's result + * @param operation CASOperation + * @param transcoder + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public boolean cas(final String key, final int exp, GetsResponse getsReponse, + final CASOperation operation, final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * @see #cas(String, int, GetsResponse, CASOperation, Transcoder) + * @param + * @param key + * @param exp + * @param getsReponse + * @param operation + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public boolean cas(final String key, final int exp, GetsResponse getsReponse, + final CASOperation operation) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * @see #cas(String, int, GetsResponse, CASOperation, Transcoder) + * @param + * @param key + * @param getsResponse + * @param operation + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public boolean cas(final String key, GetsResponse getsResponse, + final CASOperation operation) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * @see #cas(String, int, GetsResponse, CASOperation, Transcoder) + * @param + * @param key + * @param exp + * @param operation + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public boolean cas(final String key, final int exp, final CASOperation operation) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * @see #cas(String, int, GetsResponse, CASOperation, Transcoder) + * @param + * @param key + * @param operation + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public boolean cas(final String key, final CASOperation operation) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * + * @param + * @param key + * @param getsResponse + * @param operation + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public void casWithNoReply(final String key, GetsResponse getsResponse, + final CASOperation operation) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * cas noreply + * + * @param + * @param key + * @param exp + * @param getsReponse + * @param operation + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public void casWithNoReply(final String key, final int exp, GetsResponse getsReponse, + final CASOperation operation) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * @see #casWithNoReply(String, int, GetsResponse, CASOperation) + * @param + * @param key + * @param exp + * @param operation + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public void casWithNoReply(final String key, final int exp, final CASOperation operation) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * @see #casWithNoReply(String, int, GetsResponse, CASOperation) + * @param + * @param key + * @param operation + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public void casWithNoReply(final String key, final CASOperation operation) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Delete key's data item from memcached.It it is not exists,return false.
+ * time is the amount of time in seconds (or Unix time until
+ * which) the client wishes the server to refuse "add" and "replace"
+ * commands with this key. For this amount of item, the item is put into a
+ * delete queue, which means that it won't possible to retrieve it by the
+ * "get" command, but "add" and "replace" command with this key will also
+ * fail (the "set" command will succeed, however). After the time passes,
+ * the item is finally deleted from server memory.
+ * Note: This method is deprecated,because memcached 1.4.0 remove the optional argument + * "time".You can still use this method on old version,but is not recommended. + * + * @param key + * @param time + * @throws InterruptedException + * @throws MemcachedException + */ + @Deprecated + public boolean delete(final String key, final int time) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Delete key's date item from memcached + * + * @param key + * @param opTimeout Operation timeout + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + * @since 1.3.2 + */ + public boolean delete(final String key, long opTimeout) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Delete key's date item from memcached only if its cas value is the same as what was read. + * + * @param key + * @cas cas on delete to make sure the key is deleted only if its value is same as what was read. + * @param opTimeout Operation timeout + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + * @since 1.3.2 + */ + public boolean delete(final String key, long cas, long opTimeout) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Set a new expiration time for an existing item + * + * @param key item's key + * @param exp New expiration time, in seconds. Can be up to 30 days. After 30 days, is treated as + * a unix timestamp of an exact date. + * @param opTimeout operation timeout + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public boolean touch(final String key, int exp, long opTimeout) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Set a new expiration time for an existing item,using default opTimeout second. + * + * @param key item's key + * @param exp New expiration time, in seconds. Can be up to 30 days. After 30 days, is treated as + * a unix timestamp of an exact date. + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public boolean touch(final String key, int exp) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Get item and set a new expiration time for it + * + * @param + * @param key item's key + * @param newExp New expiration time, in seconds. Can be up to 30 days. After 30 days, is treated + * as a unix timestamp of an exact date. + * @param opTimeout operation timeout + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public T getAndTouch(final String key, int newExp, long opTimeout) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Get item and set a new expiration time for it,using default opTimeout + * + * @param + * @param key + * @param newExp + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public T getAndTouch(final String key, int newExp) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Bulk get items and touch them + * + * @param + * @param keyExpMap A map,key is item's key,and value is a new expiration time for the item. + * @param opTimeout operation timeout + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + // public Map getAndTouch(Map keyExpMap, + // long opTimeout) throws TimeoutException, InterruptedException, + // MemcachedException; + + /** + * Bulk get items and touch them,using default opTimeout + * + * @see #getAndTouch(Map, long) + * @param + * @param keyExpMap + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + // public Map getAndTouch(Map keyExpMap) + // throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Get all connected memcached servers's version. + * + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public Map getVersions() + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * "incr" are used to change data for some item in-place, incrementing it. The data for the item + * is treated as decimal representation of a 64-bit unsigned integer. If the current data value + * does not conform to such a representation, the commands behave as if the value were 0. Also, + * the item must already exist for incr to work; these commands won't pretend that a non-existent + * key exists with value 0; instead, it will fail.This method doesn't wait for reply. + * + * @return the new value of the item's data, after the increment operation was carried out. + * @param key + * @param num + * @throws InterruptedException + * @throws MemcachedException + */ + public long incr(final String key, final long delta) + throws TimeoutException, InterruptedException, MemcachedException; + + public long incr(final String key, final long delta, final long initValue) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * "incr" are used to change data for some item in-place, incrementing it. The data for the item + * is treated as decimal representation of a 64-bit unsigned integer. If the current data value + * does not conform to such a representation, the commands behave as if the value were 0. Also, + * the item must already exist for incr to work; these commands won't pretend that a non-existent + * key exists with value 0; instead, it will fail.This method doesn't wait for reply. + * + * @param key key + * @param num increment + * @param initValue initValue if the data is not exists. + * @param timeout operation timeout + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public long incr(final String key, final long delta, final long initValue, long timeout) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * "decr" are used to change data for some item in-place, decrementing it. The data for the item + * is treated as decimal representation of a 64-bit unsigned integer. If the current data value + * does not conform to such a representation, the commands behave as if the value were 0. Also, + * the item must already exist for decr to work; these commands won't pretend that a non-existent + * key exists with value 0; instead, it will fail.This method doesn't wait for reply. + * + * @return the new value of the item's data, after the decrement operation was carried out. + * @param key + * @param num + * @throws InterruptedException + * @throws MemcachedException + */ + public long decr(final String key, final long delta) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * @see decr + * @param key + * @param num + * @param initValue + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public long decr(final String key, final long delta, long initValue) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * "decr" are used to change data for some item in-place, decrementing it. The data for the item + * is treated as decimal representation of a 64-bit unsigned integer. If the current data value + * does not conform to such a representation, the commands behave as if the value were 0. Also, + * the item must already exist for decr to work; these commands won't pretend that a non-existent + * key exists with value 0; instead, it will fail.This method doesn't wait for reply. + * + * @param key The key + * @param num The increment + * @param initValue The initial value if the data is not exists. + * @param timeout Operation timeout + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public long decr(final String key, final long delta, long initValue, long timeout) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Make All connected memcached's data item invalid + * + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public void flushAll() throws TimeoutException, InterruptedException, MemcachedException; + + public void flushAllWithNoReply() throws InterruptedException, MemcachedException; + + /** + * Make All connected memcached's data item invalid + * + * @param timeout operation timeout + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public void flushAll(long timeout) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Invalidate all existing items immediately + * + * @param address Target memcached server + * @param timeout operation timeout + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public void flushAll(InetSocketAddress address) + throws MemcachedException, InterruptedException, TimeoutException; + + public void flushAllWithNoReply(InetSocketAddress address) + throws MemcachedException, InterruptedException; + + public void flushAll(InetSocketAddress address, long timeout) + throws MemcachedException, InterruptedException, TimeoutException; + + /** + * This method is deprecated,please use flushAll(InetSocketAddress) instead. + * + * @deprecated + * @param host + * + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + @Deprecated + public void flushAll(String host) + throws TimeoutException, InterruptedException, MemcachedException; + + public Map stats(InetSocketAddress address) + throws MemcachedException, InterruptedException, TimeoutException; + + /** + * �ョ��瑰������emcached server缁��淇℃� + * + * @param address ����板� + * @param timeout ���瓒�� + * @return + * @throws MemcachedException + * @throws InterruptedException + * @throws TimeoutException + */ + public Map stats(InetSocketAddress address, long timeout) + throws MemcachedException, InterruptedException, TimeoutException; + + /** + * Get stats from all memcached servers + * + * @param timeout + * @return server->item->value map + * @throws MemcachedException + * @throws InterruptedException + * @throws TimeoutException + */ + public Map> getStats(long timeout) + throws MemcachedException, InterruptedException, TimeoutException; + + public Map> getStats() + throws MemcachedException, InterruptedException, TimeoutException; + + /** + * Get special item stats. "stats items" for example + * + * @param item + * @return + */ + public Map> getStatsByItem(String itemName) + throws MemcachedException, InterruptedException, TimeoutException;; + + public void shutdown() throws IOException; + + public boolean delete(final String key) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * return default transcoder,default is SerializingTranscoder + * + * @return + */ + @SuppressWarnings("unchecked") + public Transcoder getTranscoder(); + + /** + * set transcoder + * + * @param transcoder + */ + @SuppressWarnings("unchecked") + public void setTranscoder(final Transcoder transcoder); + + public Map> getStatsByItem(String itemName, long timeout) + throws MemcachedException, InterruptedException, TimeoutException; + + /** + * get operation timeout setting + * + * @return + */ + public long getOpTimeout(); + + /** + * set operation timeout,default is one second. + * + * @param opTimeout + */ + public void setOpTimeout(long opTimeout); + + public Map getVersions(long timeout) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Returns available memcached servers list.This method is drepcated,please use + * getAvailableServers instead. + * + * @see #getAvailableServers() + * @return + */ + @Deprecated + public Collection getAvaliableServers(); + + /** + * Returns available memcached servers list. + * + * @return A available server collection + */ + public Collection getAvailableServers(); + + /** + * add a memcached server to MemcachedClient + * + * @param server + * @param port + * @param weight + * @throws IOException + */ + public void addServer(final String server, final int port, int weight) throws IOException; + + public void addServer(final InetSocketAddress inetSocketAddress, int weight) throws IOException; + + /** + * Delete key's data item from memcached.This method doesn't wait for reply. This method does not + * work on memcached 1.3 or later version.See + * i s s u + * e 3
+ * Note: This method is deprecated,because memcached 1.4.0 remove the optional argument + * "time".You can still use this method on old version,but is not recommended. + * + * @param key + * @param time + * @throws InterruptedException + * @throws MemcachedException + */ + @Deprecated + public void deleteWithNoReply(final String key, final int time) + throws InterruptedException, MemcachedException; + + public void deleteWithNoReply(final String key) throws InterruptedException, MemcachedException; + + /** + * "incr" are used to change data for some item in-place, incrementing it. The data for the item + * is treated as decimal representation of a 64-bit unsigned integer. If the current data value + * does not conform to such a representation, the commands behave as if the value were 0. Also, + * the item must already exist for incr to work; these commands won't pretend that a non-existent + * key exists with value 0; instead, it will fail.This method doesn't wait for reply. + * + * @param key + * @param num + * @throws InterruptedException + * @throws MemcachedException + */ + public void incrWithNoReply(final String key, final long delta) + throws InterruptedException, MemcachedException; + + /** + * "decr" are used to change data for some item in-place, decrementing it. The data for the item + * is treated as decimal representation of a 64-bit unsigned integer. If the current data value + * does not conform to such a representation, the commands behave as if the value were 0. Also, + * the item must already exist for decr to work; these commands won't pretend that a non-existent + * key exists with value 0; instead, it will fail.This method doesn't wait for reply. + * + * @param key + * @param num + * @throws InterruptedException + * @throws MemcachedException + */ + public void decrWithNoReply(final String key, final long delta) + throws InterruptedException, MemcachedException; + + /** + * Set the verbosity level of the memcached's logging output.This method will wait for reply. + * + * @param address + * @param level logging level + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public void setLoggingLevelVerbosity(InetSocketAddress address, int level) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Set the verbosity level of the memcached's logging output.This method doesn't wait for reply + * from server + * + * @param address memcached server address + * @param level logging level + * @throws InterruptedException + * @throws MemcachedException + */ + public void setLoggingLevelVerbosityWithNoReply(InetSocketAddress address, int level) + throws InterruptedException, MemcachedException; + + /** + * Add a memcached client listener + * + * @param listener + */ + public void addStateListener(MemcachedClientStateListener listener); + + /** + * Remove a memcached client listener + * + * @param listener + */ + public void removeStateListener(MemcachedClientStateListener listener); + + /** + * Get all current state listeners + * + * @return + */ + public Collection getStateListeners(); + + public void flushAllWithNoReply(int exptime) throws InterruptedException, MemcachedException; + + public void flushAll(int exptime, long timeout) + throws TimeoutException, InterruptedException, MemcachedException; + + public void flushAllWithNoReply(InetSocketAddress address, int exptime) + throws MemcachedException, InterruptedException; + + public void flushAll(InetSocketAddress address, long timeout, int exptime) + throws MemcachedException, InterruptedException, TimeoutException; + + /** + * If the memcached dump or network error cause connection closed,xmemcached would try to heal the + * connection.The interval between reconnections is 2 seconds by default. You can change that + * value by this method. + * + * @param healConnectionInterval MILLISECONDS + */ + public void setHealSessionInterval(long healConnectionInterval); + + /** + * If the memcached dump or network error cause connection closed,xmemcached would try to heal the + * connection.You can disable this behaviour by using this method:
+ * client.setEnableHealSession(false);
+ * The default value is true. + * + * @param enableHealSession + * @since 1.3.9 + */ + public void setEnableHealSession(boolean enableHealSession); + + /** + * Return the default heal session interval in milliseconds + * + * @return + */ + public long getHealSessionInterval(); + + public Protocol getProtocol(); + + /** + * Store all primitive type as string,defualt is false. + */ + public void setPrimitiveAsString(boolean primitiveAsString); + + /** + * In a high concurrent enviroment,you may want to pool memcached clients.But a xmemcached client + * has to start a reactor thread and some thread pools,if you create too many clients,the cost is + * very large. Xmemcached supports connection pool instreadof client pool.you can create more + * connections to one or more memcached servers,and these connections share the same reactor and + * thread pools,it will reduce the cost of system. + * + * @param poolSize pool size,default is one,every memcached has only one connection. + */ + public void setConnectionPoolSize(int poolSize); + + /** + * Whether to enable heart beat + * + * @param enableHeartBeat if true,then enable heartbeat,true by default + */ + public void setEnableHeartBeat(boolean enableHeartBeat); + + /** + * Enables/disables sanitizing keys by URLEncoding. + * + * @param sanitizeKey if true, then URLEncode all keys + */ + public void setSanitizeKeys(boolean sanitizeKey); + + public boolean isSanitizeKeys(); + + /** + * Get counter for key,and if the key's value is not set,then set it with 0. + * + * @param key + * @return + */ + public Counter getCounter(String key); + + /** + * Get counter for key,and if the key's value is not set,then set it with initial value. + * + * @param key + * @param initialValue + * @return + */ + public Counter getCounter(String key, long initialValue); + + /** + * Get key iterator for special memcached server.You must known that the iterator is a snapshot + * for memcached all keys,it is not real-time.The 'stats cachedump" has length limitation,so + * iterator could not visit all keys if you have many keys.Your application should not be + * dependent on this feature. + * + * @deprecated memcached 1.6.x will remove cachedump stats command,so this method will be removed + * in the future + * @param address + * @return + */ + @Deprecated + public KeyIterator getKeyIterator(InetSocketAddress address) + throws MemcachedException, InterruptedException, TimeoutException; + + /** + * Configure auth info + * + * @param map Auth info map,key is memcached server address,and value is the auth info for the + * key. + */ + public void setAuthInfoMap(Map map); + + /** + * return current all auth info + * + * @return Auth info map,key is memcached server address,and value is the auth info for the key. + */ + public Map getAuthInfoMap(); + + /** + * "incr" are used to change data for some item in-place, incrementing it. The data for the item + * is treated as decimal representation of a 64-bit unsigned integer. If the current data value + * does not conform to such a representation, the commands behave as if the value were 0. Also, + * the item must already exist for incr to work; these commands won't pretend that a non-existent + * key exists with value 0; instead, it will fail.This method doesn't wait for reply. + * + * @param key + * @param delta + * @param initValue the initial value to be added when value is not found + * @param timeout + * @param exp the initial vlaue expire time, in seconds. Can be up to 30 days. After 30 days, is + * treated as a unix timestamp of an exact date. + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + long decr(String key, long delta, long initValue, long timeout, int exp) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * "incr" are used to change data for some item in-place, incrementing it. The data for the item + * is treated as decimal representation of a 64-bit unsigned integer. If the current data value + * does not conform to such a representation, the commands behave as if the value were 0. Also, + * the item must already exist for incr to work; these commands won't pretend that a non-existent + * key exists with value 0; instead, it will fail.This method doesn't wait for reply. + * + * @param key key + * @param delta increment delta + * @param initValue the initial value to be added when value is not found + * @param timeout operation timeout + * @param exp the initial vlaue expire time, in seconds. Can be up to 30 days. After 30 days, is + * treated as a unix timestamp of an exact date. + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + long incr(String key, long delta, long initValue, long timeout, int exp) + throws TimeoutException, InterruptedException, MemcachedException; + + /** + * Return the cache instance name + * + * @return + */ + public String getName(); + + /** + * Set cache instance name + * + * @param name + */ + public void setName(String name); + + /** + * Returns reconnecting task queue,the queue is thread-safe and 'weakly consistent',but maybe you + * should not modify it at all. + * + * @return The reconnecting task queue,if the client has not been started,returns null. + */ + public Queue getReconnectRequestQueue(); + + /** + * Configure wheather to set client in failure mode.If set it to true,that means you want to + * configure client in failure mode. Failure mode is that when a memcached server is down,it would + * not taken from the server list but marked as unavailable,and then further requests to this + * server will be transformed to standby node if configured or throw an exception until it comes + * back up. + * + * @param failureMode true is to configure client in failure mode. + */ + public void setFailureMode(boolean failureMode); + + /** + * Returns if client is in failure mode. + * + * @return + */ + public boolean isFailureMode(); + + /** + * Set a key provider for pre-processing keys before sending them to memcached. + * + * @since 1.3.8 + * @param keyProvider + */ + public void setKeyProvider(KeyProvider keyProvider); + + /** + * Returns maximum number of timeout exception for closing connection. + * + * @return + */ + public int getTimeoutExceptionThreshold(); + + /** + * Set maximum number of timeout exception for closing connection.You can set it to be a large + * value to disable this feature. + * + * @see #DEFAULT_MAX_TIMEOUTEXCEPTION_THRESHOLD + * @param timeoutExceptionThreshold + */ + public void setTimeoutExceptionThreshold(int timeoutExceptionThreshold); + + /** + * Invalidate all namespace under the namespace using the default operation timeout. + * + * @since 1.4.2 + * @param ns the namespace + * @throws MemcachedException + * @throws InterruptedException + * @throws TimeoutException + */ + public abstract void invalidateNamespace(String ns) + throws MemcachedException, InterruptedException, TimeoutException; + + /** + * Invalidate all items under the namespace. + * + * @since 1.4.2 + * @param ns the namespace + * @param opTimeout operation timeout in milliseconds. + * @throws MemcachedException + * @throws InterruptedException + * @throws TimeoutException + */ + public void invalidateNamespace(String ns, long opTimeout) + throws MemcachedException, InterruptedException, TimeoutException; + + /** + * Remove current namespace set for this memcached client.It must begin with + * {@link #beginWithNamespace(String)} method. + * + * @see #beginWithNamespace(String) + */ + public void endWithNamespace(); + + /** + * set current namespace for following operations with memcached client.It must be ended with + * {@link #endWithNamespace()} method.For example: + * + *
+   * memcachedClient.beginWithNamespace(userId);
+   * try {
+   *   memcachedClient.set("username", 0, username);
+   *   memcachedClient.set("email", 0, email);
+   * } finally {
+   *   memcachedClient.endWithNamespace();
+   * }
+   * 
+ * + * @see #endWithNamespace() + * @see #withNamespace(String, MemcachedClientCallable) + * @param ns + */ + public void beginWithNamespace(String ns); + + /** + * With the namespae to do something with current memcached client.All operations with memcached + * client done in callable will be under the namespace. {@link #beginWithNamespace(String)} and + * {@link #endWithNamespace()} will called around automatically. For example: + * + *
+   *   memcachedClient.withNamespace(userId,new MemcachedClientCallable{
+   *     public Void call(MemcachedClient client) throws MemcachedException,
+   * 	InterruptedException, TimeoutException{
+   *      client.set("username",0,username);
+   *      client.set("email",0,email);
+   *      return null;
+   *     }
+   *   });
+   *   //invalidate all items under the namespace.
+   *   memcachedClient.invalidateNamespace(userId);
+   * 
+ * + * @since 1.4.2 + * @param ns + * @param callable + * @see #beginWithNamespace(String) + * @see #endWithNamespace() + * @return + */ + public T withNamespace(String ns, MemcachedClientCallable callable) + throws MemcachedException, InterruptedException, TimeoutException; + +} diff --git a/src/main/java/net/rubyeye/xmemcached/MemcachedClientBuilder.java b/src/main/java/net/rubyeye/xmemcached/MemcachedClientBuilder.java index 8ee6d5007..c8a6eccfd 100644 --- a/src/main/java/net/rubyeye/xmemcached/MemcachedClientBuilder.java +++ b/src/main/java/net/rubyeye/xmemcached/MemcachedClientBuilder.java @@ -4,11 +4,9 @@ import java.net.InetSocketAddress; import java.util.List; import java.util.Map; - import net.rubyeye.xmemcached.auth.AuthInfo; import net.rubyeye.xmemcached.buffer.BufferAllocator; import net.rubyeye.xmemcached.transcoders.Transcoder; - import com.google.code.yanf4j.config.Configuration; import com.google.code.yanf4j.core.SocketOption; @@ -20,279 +18,264 @@ */ public interface MemcachedClientBuilder { - /** - * - * @return net.rubyeye.xmemcached.MemcachedSessionLocator - */ - public MemcachedSessionLocator getSessionLocator(); - - /** - * Set the XmemcachedClient's session locator.Use - * ArrayMemcachedSessionLocator by default.If you want to choose consistent - * hash strategy,set it to KetamaMemcachedSessionLocator - * - * @param sessionLocator - */ - public void setSessionLocator(MemcachedSessionLocator sessionLocator); - - public BufferAllocator getBufferAllocator(); - - /** - * Set nio ByteBuffer's allocator.Use SimpleBufferAllocator by default.You - * can choose CachedBufferAllocator. - * - * @param bufferAllocator - */ - public void setBufferAllocator(BufferAllocator bufferAllocator); - - /** - * Return the default networking's configuration,you can change them. - * - * @return - */ - public Configuration getConfiguration(); - - /** - * Set the XmemcachedClient's networking - * configuration(reuseAddr,receiveBufferSize,tcpDelay etc.) - * - * @param configuration - */ - public void setConfiguration(Configuration configuration); - - /** - * Build MemcachedClient by current options. - * - * @return - * @throws IOException - */ - public MemcachedClient build() throws IOException; - - /** - * In a high concurrent enviroment,you may want to pool memcached - * clients.But a xmemcached client has to start a reactor thread and some - * thread pools,if you create too many clients,the cost is very large. - * Xmemcached supports connection pool instead of client pool.you can create - * more connections to one or more memcached servers,and these connections - * share the same reactor and thread pools,it will reduce the cost of - * system. - * - * @param poolSize - * pool size,default is 1 - */ - public void setConnectionPoolSize(int poolSize); - - /** - * Set xmemcached's transcoder,it is used for seriailizing - * - * @return - */ - @SuppressWarnings("unchecked") - public Transcoder getTranscoder(); - - @SuppressWarnings("unchecked") - public void setTranscoder(Transcoder transcoder); - - /** - * get xmemcached's command factory - * - * @return - */ - public CommandFactory getCommandFactory(); - - /** - * Add a state listener - * - * @param stateListener - */ - public void addStateListener(MemcachedClientStateListener stateListener); - - /** - * Remove a state listener - * - * @param stateListener - */ - public void removeStateListener(MemcachedClientStateListener stateListener); - - /** - * Set state listeners,replace current list - * - * @param stateListeners - */ - public void setStateListeners( - List stateListeners); - - /** - * set xmemcached's command factory.Default is TextCommandFactory,which - * implements memcached text protocol. - * - * @param commandFactory - */ - public void setCommandFactory(CommandFactory commandFactory); - - /** - * Set tcp socket option - * - * @param socketOption - * @param value - */ - @SuppressWarnings("unchecked") - public void setSocketOption(SocketOption socketOption, Object value); - - /** - * Get all tcp socket options - * - * @return - */ - @SuppressWarnings("unchecked") - public Map getSocketOptions(); - - /** - * Configure auth info - * - * @param map - * Auth info map,key is memcached server address,and value is the - * auth info for the key. - */ - public void setAuthInfoMap(Map map); - - /** - * return current all auth info - * - * @return Auth info map,key is memcached server address,and value is the - * auth info for the key. - */ - public Map getAuthInfoMap(); - - /** - * Add auth info for memcached server - * - * @param address - * @param authInfo - */ - public void addAuthInfo(InetSocketAddress address, AuthInfo authInfo); - - /** - * Remove auth info for memcached server - * - * @param address - */ - public void removeAuthInfo(InetSocketAddress address); - - /** - * Return the cache instance name - * - * @return - */ - public String getName(); - - /** - * Set cache instance name - * - * @param name - */ - public void setName(String name); - - /** - * Configure wheather to set client in failure mode.If set it to true,that - * means you want to configure client in failure mode. Failure mode is that - * when a memcached server is down,it would not taken from the server list - * but marked as unavailable,and then further requests to this server will - * be transformed to standby node if configured or throw an exception until - * it comes back up. - * - * @param failureMode - * true is to configure client in failure mode. - */ - public void setFailureMode(boolean failureMode); - - /** - * Returns if client is in failure mode. - * - * @return - */ - public boolean isFailureMode(); - - /** - * Returns connect timeout in milliseconds - * - * @return connect timeout - */ - public long getConnectTimeout(); - - /** - * Set connect timeout in milliseconds - * - * @see net.rubyeye.xmemcached.MemcachedClient#DEFAULT_CONNECT_TIMEOUT - * - * @param connectTimeout - */ - public void setConnectTimeout(long connectTimeout); - - /** - * Enables/disables sanitizing keys by URLEncoding. - * - * @param sanitizeKey - * if true, then URLEncode all keys - */ - public void setSanitizeKeys(boolean sanitizeKeys); - - /** - * Set a key provider for pre-processing keys before sending them to - * memcached. - * - * @since 1.3.8 - * @param keyProvider - */ - public void setKeyProvider(KeyProvider keyProvider); - - /** - * Set max queued noreply operations number - * - * @see MemcachedClient#DEFAULT_MAX_QUEUED_NOPS - * @param maxQueuedNoReplyOperations - * @since 1.3.8 - */ - public void setMaxQueuedNoReplyOperations(int maxQueuedNoReplyOperations); - - /** - * If the memcached dump or network error cause connection closed,xmemcached - * would try to heal the connection.The interval between reconnections is 2 - * seconds by default. You can change that value by this method. - * - * @since 1.3.9 - * @param healConnectionInterval - * MILLISECONDS - */ - public void setHealSessionInterval(long healConnectionInterval); - - /** - * If the memcached dump or network error cause connection closed,xmemcached - * would try to heal the connection.You can disable this behaviour by using - * this method:
- * client.setEnableHealSession(false);
- * The default value is true. - * - * @param enableHealSession - * @since 1.3.9 - */ - public void setEnableHealSession(boolean enableHealSession); - - /** - * Set default operation timeout. - * - * @param opTimeout - * Operation timeout value in milliseconds. - * @since 1.4.1 - */ - public void setOpTimeout(long opTimeout); - - /** - * Returns the default operation timeout in milliseconds. - * - * @since 1.4.1 - * @return - */ - public long getOpTimeout(); - -} \ No newline at end of file + /** + * + * @return net.rubyeye.xmemcached.MemcachedSessionLocator + */ + public MemcachedSessionLocator getSessionLocator(); + + /** + * Set the XmemcachedClient's session locator.Use ArrayMemcachedSessionLocator by default.If you + * want to choose consistent hash strategy,set it to KetamaMemcachedSessionLocator + * + * @param sessionLocator + */ + public void setSessionLocator(MemcachedSessionLocator sessionLocator); + + public BufferAllocator getBufferAllocator(); + + /** + * Set nio ByteBuffer's allocator.Use SimpleBufferAllocator by default.You can choose + * CachedBufferAllocator. + * + * @param bufferAllocator + */ + public void setBufferAllocator(BufferAllocator bufferAllocator); + + /** + * Return the default networking's configuration,you can change them. + * + * @return + */ + public Configuration getConfiguration(); + + /** + * Set the XmemcachedClient's networking configuration(reuseAddr,receiveBufferSize,tcpDelay etc.) + * + * @param configuration + */ + public void setConfiguration(Configuration configuration); + + /** + * Build MemcachedClient by current options. + * + * @return + * @throws IOException + */ + public MemcachedClient build() throws IOException; + + /** + * In a high concurrent enviroment,you may want to pool memcached clients.But a xmemcached client + * has to start a reactor thread and some thread pools,if you create too many clients,the cost is + * very large. Xmemcached supports connection pool instead of client pool.you can create more + * connections to one or more memcached servers,and these connections share the same reactor and + * thread pools,it will reduce the cost of system. + * + * @param poolSize pool size,default is 1 + */ + public void setConnectionPoolSize(int poolSize); + + /** + * Set xmemcached's transcoder,it is used for seriailizing + * + * @return + */ + @SuppressWarnings("unchecked") + public Transcoder getTranscoder(); + + @SuppressWarnings("unchecked") + public void setTranscoder(Transcoder transcoder); + + /** + * get xmemcached's command factory + * + * @return + */ + public CommandFactory getCommandFactory(); + + /** + * Add a state listener + * + * @param stateListener + */ + public void addStateListener(MemcachedClientStateListener stateListener); + + /** + * Remove a state listener + * + * @param stateListener + */ + public void removeStateListener(MemcachedClientStateListener stateListener); + + /** + * Set state listeners,replace current list + * + * @param stateListeners + */ + public void setStateListeners(List stateListeners); + + /** + * set xmemcached's command factory.Default is TextCommandFactory,which implements memcached text + * protocol. + * + * @param commandFactory + */ + public void setCommandFactory(CommandFactory commandFactory); + + /** + * Set tcp socket option + * + * @param socketOption + * @param value + */ + @SuppressWarnings("unchecked") + public void setSocketOption(SocketOption socketOption, Object value); + + /** + * Get all tcp socket options + * + * @return + */ + @SuppressWarnings("unchecked") + public Map getSocketOptions(); + + /** + * Configure auth info + * + * @param map Auth info map,key is memcached server address,and value is the auth info for the + * key. + */ + public void setAuthInfoMap(Map map); + + /** + * return current all auth info + * + * @return Auth info map,key is memcached server address,and value is the auth info for the key. + */ + public Map getAuthInfoMap(); + + /** + * Add auth info for memcached server + * + * @param address + * @param authInfo + */ + public void addAuthInfo(InetSocketAddress address, AuthInfo authInfo); + + /** + * Remove auth info for memcached server + * + * @param address + */ + public void removeAuthInfo(InetSocketAddress address); + + /** + * Return the cache instance name + * + * @return + */ + public String getName(); + + /** + * Set cache instance name + * + * @param name + */ + public void setName(String name); + + /** + * Configure wheather to set client in failure mode.If set it to true,that means you want to + * configure client in failure mode. Failure mode is that when a memcached server is down,it would + * not taken from the server list but marked as unavailable,and then further requests to this + * server will be transformed to standby node if configured or throw an exception until it comes + * back up. + * + * @param failureMode true is to configure client in failure mode. + */ + public void setFailureMode(boolean failureMode); + + /** + * Returns if client is in failure mode. + * + * @return + */ + public boolean isFailureMode(); + + /** + * Returns connect timeout in milliseconds + * + * @return connect timeout + */ + public long getConnectTimeout(); + + /** + * Set connect timeout in milliseconds + * + * @see net.rubyeye.xmemcached.MemcachedClient#DEFAULT_CONNECT_TIMEOUT + * + * @param connectTimeout + */ + public void setConnectTimeout(long connectTimeout); + + /** + * Enables/disables sanitizing keys by URLEncoding. + * + * @param sanitizeKey if true, then URLEncode all keys + */ + public void setSanitizeKeys(boolean sanitizeKeys); + + /** + * Set a key provider for pre-processing keys before sending them to memcached. + * + * @since 1.3.8 + * @param keyProvider + */ + public void setKeyProvider(KeyProvider keyProvider); + + /** + * Set max queued noreply operations number + * + * @see MemcachedClient#DEFAULT_MAX_QUEUED_NOPS + * @param maxQueuedNoReplyOperations + * @since 1.3.8 + */ + public void setMaxQueuedNoReplyOperations(int maxQueuedNoReplyOperations); + + /** + * If the memcached dump or network error cause connection closed,xmemcached would try to heal the + * connection.The interval between reconnections is 2 seconds by default. You can change that + * value by this method. + * + * @since 1.3.9 + * @param healConnectionInterval MILLISECONDS + */ + public void setHealSessionInterval(long healConnectionInterval); + + /** + * If the memcached dump or network error cause connection closed,xmemcached would try to heal the + * connection.You can disable this behaviour by using this method:
+ * client.setEnableHealSession(false);
+ * The default value is true. + * + * @param enableHealSession + * @since 1.3.9 + */ + public void setEnableHealSession(boolean enableHealSession); + + /** + * Set default operation timeout. + * + * @param opTimeout Operation timeout value in milliseconds. + * @since 1.4.1 + */ + public void setOpTimeout(long opTimeout); + + /** + * Returns the default operation timeout in milliseconds. + * + * @since 1.4.1 + * @return + */ + public long getOpTimeout(); + +} diff --git a/src/main/java/net/rubyeye/xmemcached/MemcachedClientCallable.java b/src/main/java/net/rubyeye/xmemcached/MemcachedClientCallable.java index 610464f14..31a2f57c7 100644 --- a/src/main/java/net/rubyeye/xmemcached/MemcachedClientCallable.java +++ b/src/main/java/net/rubyeye/xmemcached/MemcachedClientCallable.java @@ -1,31 +1,30 @@ -package net.rubyeye.xmemcached; - -import java.util.concurrent.TimeoutException; - -import net.rubyeye.xmemcached.exception.MemcachedException; - -/** - * MemcachedClient callable when using namespace in xmemcached.For example: - * - *
- *   memcachedClient.withNamespace(userId,new MemcachedClientCallable{
- *     public Void call(MemcachedClient client) throws MemcachedException,
- * 			InterruptedException, TimeoutException{
- *      client.set("username",0,username);
- *      client.set("email",0,email);
- *      return null;
- *     }
- *   }); 
- *   //invalidate all items under the namespace.
- *   memcachedClient.invalidateNamespace(userId);
- * 
- * - * @author dennis - * @see MemcachedClient#withNamespace(String, MemcachedClientCallable) - * @since 1.4.2 - * @param - */ -public interface MemcachedClientCallable { - public T call(MemcachedClient client) - throws MemcachedException, InterruptedException, TimeoutException; -} +package net.rubyeye.xmemcached; + +import java.util.concurrent.TimeoutException; +import net.rubyeye.xmemcached.exception.MemcachedException; + +/** + * MemcachedClient callable when using namespace in xmemcached.For example: + * + *
+ *   memcachedClient.withNamespace(userId,new MemcachedClientCallable{
+ *     public Void call(MemcachedClient client) throws MemcachedException,
+ * 			InterruptedException, TimeoutException{
+ *      client.set("username",0,username);
+ *      client.set("email",0,email);
+ *      return null;
+ *     }
+ *   }); 
+ *   //invalidate all items under the namespace.
+ *   memcachedClient.invalidateNamespace(userId);
+ * 
+ * + * @author dennis + * @see MemcachedClient#withNamespace(String, MemcachedClientCallable) + * @since 1.4.2 + * @param + */ +public interface MemcachedClientCallable { + public T call(MemcachedClient client) + throws MemcachedException, InterruptedException, TimeoutException; +} diff --git a/src/main/java/net/rubyeye/xmemcached/MemcachedClientStateListener.java b/src/main/java/net/rubyeye/xmemcached/MemcachedClientStateListener.java index 6a1b24b03..173084e54 100644 --- a/src/main/java/net/rubyeye/xmemcached/MemcachedClientStateListener.java +++ b/src/main/java/net/rubyeye/xmemcached/MemcachedClientStateListener.java @@ -1,68 +1,59 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached; import java.net.InetSocketAddress; /** - * MemcachedClient state listener.When client startup,shutdown,connected to a - * memcached server or disconnected happened,client will notify the listener - * instance which implemented this interface.Please don't do any operations - * which may block in these callback methods. + * MemcachedClient state listener.When client startup,shutdown,connected to a memcached server or + * disconnected happened,client will notify the listener instance which implemented this + * interface.Please don't do any operations which may block in these callback methods. * * @author dennis * */ public interface MemcachedClientStateListener { - /** - * After client is started. - * - * @param memcachedClient - */ - public void onStarted(MemcachedClient memcachedClient); + /** + * After client is started. + * + * @param memcachedClient + */ + public void onStarted(MemcachedClient memcachedClient); - /** - * After client is shutdown. - * - * @param memcachedClient - */ - public void onShutDown(MemcachedClient memcachedClient); + /** + * After client is shutdown. + * + * @param memcachedClient + */ + public void onShutDown(MemcachedClient memcachedClient); - /** - * After a memcached server is connected,don't do any operations may block - * here. - * - * @param memcachedClient - * @param inetSocketAddress - */ - public void onConnected(MemcachedClient memcachedClient, - InetSocketAddress inetSocketAddress); + /** + * After a memcached server is connected,don't do any operations may block here. + * + * @param memcachedClient + * @param inetSocketAddress + */ + public void onConnected(MemcachedClient memcachedClient, InetSocketAddress inetSocketAddress); - /** - * After a memcached server is disconnected,don't do any operations may - * block here. - * - * @param memcachedClient - * @param inetSocketAddress - */ - public void onDisconnected(MemcachedClient memcachedClient, - InetSocketAddress inetSocketAddress); + /** + * After a memcached server is disconnected,don't do any operations may block here. + * + * @param memcachedClient + * @param inetSocketAddress + */ + public void onDisconnected(MemcachedClient memcachedClient, InetSocketAddress inetSocketAddress); - /** - * When exceptions occur - * - * @param memcachedClient - * @param throwable - */ - public void onException(MemcachedClient memcachedClient, - Throwable throwable); + /** + * When exceptions occur + * + * @param memcachedClient + * @param throwable + */ + public void onException(MemcachedClient memcachedClient, Throwable throwable); } diff --git a/src/main/java/net/rubyeye/xmemcached/MemcachedOptimizer.java b/src/main/java/net/rubyeye/xmemcached/MemcachedOptimizer.java index 99504fa38..e4d758eb2 100644 --- a/src/main/java/net/rubyeye/xmemcached/MemcachedOptimizer.java +++ b/src/main/java/net/rubyeye/xmemcached/MemcachedOptimizer.java @@ -1,42 +1,35 @@ -/** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 - */ -/** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 net.rubyeye.xmemcached; - -import java.util.Queue; - -import net.rubyeye.xmemcached.buffer.BufferAllocator; -import net.rubyeye.xmemcached.command.Command; - -/** - * xmemcached Optimizer - * - * @author dennis - */ -public interface MemcachedOptimizer { - @SuppressWarnings("unchecked") - Command optimize(final Command currentCommand, final Queue writeQueue, - final Queue executingCmds, int sendBufferSize); - - @Deprecated - public void setBufferAllocator(BufferAllocator bufferAllocator); -} +/** + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 + */ +/** + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached; + +import java.util.Queue; +import net.rubyeye.xmemcached.buffer.BufferAllocator; +import net.rubyeye.xmemcached.command.Command; + +/** + * xmemcached Optimizer + * + * @author dennis + */ +public interface MemcachedOptimizer { + @SuppressWarnings("unchecked") + Command optimize(final Command currentCommand, final Queue writeQueue, + final Queue executingCmds, int sendBufferSize); + + @Deprecated + public void setBufferAllocator(BufferAllocator bufferAllocator); +} diff --git a/src/main/java/net/rubyeye/xmemcached/MemcachedSessionLocator.java b/src/main/java/net/rubyeye/xmemcached/MemcachedSessionLocator.java index c62cb0411..b72c155d2 100644 --- a/src/main/java/net/rubyeye/xmemcached/MemcachedSessionLocator.java +++ b/src/main/java/net/rubyeye/xmemcached/MemcachedSessionLocator.java @@ -1,18 +1,14 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached; import java.util.Collection; - import com.google.code.yanf4j.core.Session; /** @@ -22,27 +18,25 @@ * */ public interface MemcachedSessionLocator { - /** - * Returns a session by special key. - * - * @param key - * @return - */ - public Session getSessionByKey(final String key); + /** + * Returns a session by special key. + * + * @param key + * @return + */ + public Session getSessionByKey(final String key); - /** - * Update sessions when session was added or removed. - * - * @param list - * The newer sessions - */ - public void updateSessions(final Collection list); + /** + * Update sessions when session was added or removed. + * + * @param list The newer sessions + */ + public void updateSessions(final Collection list); - /** - * Configure failure mode - * - * @param failureMode - * true is using failure mode - */ - public void setFailureMode(boolean failureMode); + /** + * Configure failure mode + * + * @param failureMode true is using failure mode + */ + public void setFailureMode(boolean failureMode); } diff --git a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java index a9f6dc2c3..f06a315fe 100644 --- a/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java +++ b/src/main/java/net/rubyeye/xmemcached/XMemcachedClient.java @@ -1,13 +1,10 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached; @@ -34,7 +31,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; - import net.rubyeye.xmemcached.auth.AuthInfo; import net.rubyeye.xmemcached.buffer.BufferAllocator; import net.rubyeye.xmemcached.buffer.SimpleBufferAllocator; @@ -66,10 +62,8 @@ import net.rubyeye.xmemcached.utils.ByteUtils; import net.rubyeye.xmemcached.utils.InetSocketAddressWrapper; import net.rubyeye.xmemcached.utils.Protocol; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import com.google.code.yanf4j.config.Configuration; import com.google.code.yanf4j.core.Session; import com.google.code.yanf4j.core.SocketOption; @@ -81,2767 +75,2548 @@ * @author dennis(killme2008@gmail.com) * */ -public class XMemcachedClient - implements - XMemcachedClientMBean, - MemcachedClient { - - private static final Logger log = LoggerFactory - .getLogger(XMemcachedClient.class); - protected MemcachedSessionLocator sessionLocator; - private volatile boolean shutdown; - protected MemcachedConnector connector; - @SuppressWarnings("unchecked") - private Transcoder transcoder; - private boolean sanitizeKeys; - private MemcachedHandler memcachedHandler; - protected CommandFactory commandFactory; - protected long opTimeout = DEFAULT_OP_TIMEOUT; - private long connectTimeout = DEFAULT_CONNECT_TIMEOUT; - protected int connectionPoolSize = DEFAULT_CONNECTION_POOL_SIZE; - protected int maxQueuedNoReplyOperations = DEFAULT_MAX_QUEUED_NOPS; - - protected final AtomicInteger serverOrderCount = new AtomicInteger(); - - private Map authInfoMap = new HashMap(); - - private String name; // cache name - - private boolean failureMode; - - private int timeoutExceptionThreshold = DEFAULT_MAX_TIMEOUTEXCEPTION_THRESHOLD; - - private final CopyOnWriteArrayList stateListenerAdapters = new CopyOnWriteArrayList(); - private Thread shutdownHookThread; - - private volatile boolean isHutdownHookCalled = false; - // key provider for pre-processing keys before sending them to memcached - // added by dennis,2012-07-14 - private KeyProvider keyProvider = DefaultKeyProvider.INSTANCE; - /** - * namespace thread local. - */ - public static final ThreadLocal NAMESPACE_LOCAL = new ThreadLocal(); - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#setMergeFactor(int) - */ - public final void setMergeFactor(final int mergeFactor) { - if (mergeFactor < 0) { - throw new IllegalArgumentException("mergeFactor<0"); - } - this.connector.setMergeFactor(mergeFactor); - } - - public int getTimeoutExceptionThreshold() { - return this.timeoutExceptionThreshold; - } - - public void setTimeoutExceptionThreshold(int timeoutExceptionThreshold) { - if (timeoutExceptionThreshold <= 0) { - throw new IllegalArgumentException( - "Illegal timeoutExceptionThreshold value " - + timeoutExceptionThreshold); - } - if (timeoutExceptionThreshold < 100) { - log.warn( - "Too small timeoutExceptionThreshold value may cause connections disconnect/reconnect frequently."); - } - this.timeoutExceptionThreshold = timeoutExceptionThreshold; - } - - public T withNamespace(String ns, MemcachedClientCallable callable) - throws MemcachedException, InterruptedException, TimeoutException { - this.beginWithNamespace(ns); - try { - return callable.call(this); - } finally { - this.endWithNamespace(); - } - } - - public void endWithNamespace() { - NAMESPACE_LOCAL.remove(); - } - - public void beginWithNamespace(String ns) { - if (ns == null || ns.trim().length() == 0) { - throw new IllegalArgumentException("Blank namespace"); - } - if (NAMESPACE_LOCAL.get() != null) { - throw new IllegalStateException("Previous namespace wasn't ended."); - } - NAMESPACE_LOCAL.set(ns); - } - - public KeyProvider getKeyProvider() { - return this.keyProvider; - } - - public void setKeyProvider(KeyProvider keyProvider) { - if (keyProvider == null) { - throw new IllegalArgumentException("Null key provider"); - } - this.keyProvider = keyProvider; - } - - public final MemcachedSessionLocator getSessionLocator() { - return this.sessionLocator; - } - - public final CommandFactory getCommandFactory() { - return this.commandFactory; - } - - public String getName() { - return this.name; - } - - public void setName(String name) { - this.name = name; - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#getConnectTimeout() - */ - public long getConnectTimeout() { - return this.connectTimeout; - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#setConnectTimeout(long) - */ - public void setConnectTimeout(long connectTimeout) { - if (connectTimeout < 0) { - throw new IllegalArgumentException("connectTimeout<0"); - } - this.connectTimeout = connectTimeout; - } - - public void setEnableHeartBeat(boolean enableHeartBeat) { - this.memcachedHandler.setEnableHeartBeat(enableHeartBeat); - } - - /** - * get operation timeout setting - * - * @return - */ - public final long getOpTimeout() { - return this.opTimeout; - } - - /** - * set operation timeout,default is one second. - * - * @param opTimeout - */ - public final void setOpTimeout(long opTimeout) { - if (opTimeout < 0) { - throw new IllegalArgumentException("opTimeout<0"); - } - this.opTimeout = opTimeout; - } - - public void setHealSessionInterval(long healConnectionInterval) { - if (healConnectionInterval <= 0) { - throw new IllegalArgumentException( - "Invalid heal session interval:" + healConnectionInterval); - } - if (null != this.connector) { - this.connector.setHealSessionInterval(healConnectionInterval); - } else { - throw new IllegalStateException("The client hasn't been started"); - } - } - - public long getHealSessionInterval() { - if (null != this.connector) { - return this.connector.getHealSessionInterval(); - } - return -1L; - } - - public Map getAuthInfoMap() { - return this.authInfoMap; - } - - public void setAuthInfoMap(Map map) { - this.authInfoMap = map; - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#getConnector() - */ - public final Connector getConnector() { - return this.connector; - } - - /* - * (non-Javadoc) - * - * @see - * net.rubyeye.xmemcached.MemcachedClient#setOptimizeMergeBuffer(boolean) - */ - public final void setOptimizeMergeBuffer( - final boolean optimizeMergeBuffer) { - this.connector.setOptimizeMergeBuffer(optimizeMergeBuffer); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#isShutdown() - */ - public final boolean isShutdown() { - return this.shutdown; - } - - @SuppressWarnings("unchecked") - private final GetsResponse gets0(final String key, - final byte[] keyBytes, final Transcoder transcoder) - throws MemcachedException, TimeoutException, InterruptedException { - GetsResponse result = (GetsResponse) this.fetch0(key, keyBytes, - CommandType.GETS_ONE, this.opTimeout, transcoder); - return result; - } - - protected final Session sendCommand(final Command cmd) - throws MemcachedException { - if (this.shutdown) { - throw new MemcachedException("Xmemcached is stopped"); - } - return this.connector.send(cmd); - } - - /** - * XMemcached constructor,default weight is 1 - * - * @param server - * �����P - * @param port - * ����ㄧ��� - * @throws IOException - */ - public XMemcachedClient(final String server, final int port) - throws IOException { - this(server, port, 1); - } - - /** - * XMemcached constructor - * - * @param host - * server host - * @param port - * server port - * @param weight - * server weight - * @throws IOException - */ - public XMemcachedClient(final String host, final int port, int weight) - throws IOException { - super(); - if (weight <= 0) { - throw new IllegalArgumentException("weight<=0"); - } - this.checkServerPort(host, port); - this.buildConnector(new ArrayMemcachedSessionLocator(), - new SimpleBufferAllocator(), - XMemcachedClientBuilder.getDefaultConfiguration(), - XMemcachedClientBuilder.getDefaultSocketOptions(), - new TextCommandFactory(), new SerializingTranscoder()); - this.start0(); - this.connect( - new InetSocketAddressWrapper(this.newSocketAddress(host, port), - this.serverOrderCount.incrementAndGet(), weight, null)); - } - - protected InetSocketAddress newSocketAddress(final String server, - final int port) { - return new InetSocketAddress(server, port); - } - - private void checkServerPort(String server, int port) { - if (server == null || server.length() == 0) { - throw new IllegalArgumentException(); - } - if (port <= 0) { - throw new IllegalArgumentException(); - } - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#addServer(java.lang.String, - * int) - */ - public final void addServer(final String server, final int port) - throws IOException { - this.addServer(server, port, 1); - } - - /** - * add a memcached server to MemcachedClient - * - * @param server - * @param port - * @param weight - * @throws IOException - */ - public final void addServer(final String server, final int port, int weight) - throws IOException { - if (weight <= 0) { - throw new IllegalArgumentException("weight<=0"); - } - this.checkServerPort(server, port); - this.connect(new InetSocketAddressWrapper( - this.newSocketAddress(server, port), - this.serverOrderCount.incrementAndGet(), weight, null)); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#addServer(java.net. - * InetSocketAddress ) - */ - public final void addServer(final InetSocketAddress inetSocketAddress) - throws IOException { - this.addServer(inetSocketAddress, 1); - } - - public final void addServer(final InetSocketAddress inetSocketAddress, - int weight) throws IOException { - if (inetSocketAddress == null) { - throw new IllegalArgumentException("Null InetSocketAddress"); - } - if (weight <= 0) { - throw new IllegalArgumentException("weight<=0"); - } - this.connect(new InetSocketAddressWrapper(inetSocketAddress, - this.serverOrderCount.incrementAndGet(), weight, null)); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#addServer(java.lang.String) - */ - public final void addServer(String hostList) throws IOException { - Map addresses = AddrUtil - .getAddressMap(hostList); - if (addresses != null && addresses.size() > 0) { - for (Map.Entry entry : addresses - .entrySet()) { - final InetSocketAddress mainNodeAddr = entry.getKey(); - final InetSocketAddress standbyNodeAddr = entry.getValue(); - this.connect(new InetSocketAddressWrapper(mainNodeAddr, - this.serverOrderCount.incrementAndGet(), 1, null)); - if (standbyNodeAddr != null) { - this.connect(new InetSocketAddressWrapper(standbyNodeAddr, - this.serverOrderCount.incrementAndGet(), 1, - mainNodeAddr)); - } - } - } - } - - public void addOneServerWithWeight(String server, int weight) - throws IOException { - Map addresses = AddrUtil - .getAddressMap(server); - if (addresses == null) { - throw new IllegalArgumentException("Null Server"); - } - if (addresses.size() != 1) { - throw new IllegalArgumentException( - "Please add one server at one time"); - } - if (weight <= 0) { - throw new IllegalArgumentException("weight<=0"); - } - if (addresses != null && addresses.size() > 0) { - for (Map.Entry entry : addresses - .entrySet()) { - final InetSocketAddress mainNodeAddr = entry.getKey(); - final InetSocketAddress standbyNodeAddr = entry.getValue(); - this.connect(new InetSocketAddressWrapper(mainNodeAddr, - this.serverOrderCount.incrementAndGet(), 1, null)); - if (standbyNodeAddr != null) { - this.connect(new InetSocketAddressWrapper(standbyNodeAddr, - this.serverOrderCount.incrementAndGet(), 1, - mainNodeAddr)); - } - } - } - - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#getServersDescription() - */ - public final List getServersDescription() { - final List result = new ArrayList(); - for (Session session : this.connector.getSessionSet()) { - InetSocketAddress socketAddress = session.getRemoteSocketAddress(); - int weight = ((MemcachedSession) session) - .getInetSocketAddressWrapper().getWeight(); - result.add(SystemUtils.getRawAddress(socketAddress) + ":" - + socketAddress.getPort() + "(weight=" + weight + ")"); - } - return result; - } - - public final void setServerWeight(String server, int weight) { - InetSocketAddress socketAddress = AddrUtil.getOneAddress(server); - Queue sessionQueue = this.connector - .getSessionByAddress(socketAddress); - if (sessionQueue == null) { - throw new IllegalArgumentException("There is no server " + server); - } - for (Session session : sessionQueue) { - if (session != null) { - ((MemcachedTCPSession) session).getInetSocketAddressWrapper() - .setWeight(weight); - } - } - this.connector.updateSessions(); - } - - /* - * (non-Javadoc) - * - * @see - * net.rubyeye.xmemcached.MemcachedClient#removeServer(java.lang.String) - */ - public final void removeServer(String hostList) { - List addresses = AddrUtil.getAddresses(hostList); - if (addresses != null && addresses.size() > 0) { - for (InetSocketAddress address : addresses) { - removeAddr(address); - } - - } - - } - - protected void removeAddr(InetSocketAddress address) { - // Close main sessions - Queue sessionQueue = this.connector - .getSessionByAddress(address); - if (sessionQueue != null) { - for (Session session : sessionQueue) { - if (session != null) { - // Disable auto reconnection - ((MemcachedSession) session).setAllowReconnect(false); - // Close connection - ((MemcachedSession) session).quit(); - } - } - } - // Close standby sessions - List standBySession = this.connector - .getStandbySessionListByMainNodeAddr(address); - if (standBySession != null) { - for (Session session : standBySession) { - if (session != null) { - this.connector.removeReconnectRequest( - session.getRemoteSocketAddress()); - // Disable auto reconnection - ((MemcachedSession) session).setAllowReconnect(false); - // Close connection - ((MemcachedSession) session).quit(); - } - } - } - this.connector.removeReconnectRequest(address); - } - - protected void connect( - final InetSocketAddressWrapper inetSocketAddressWrapper) - throws IOException { - // creat connection pool - InetSocketAddress inetSocketAddress = inetSocketAddressWrapper - .getInetSocketAddress(); - if (this.connectionPoolSize > 1) { - log.warn( - "You are using connection pool for xmemcached client,it's not recommended unless you have test it that it can boost performance in your app."); - } - for (int i = 0; i < this.connectionPoolSize; i++) { - Future future = null; - boolean connected = false; - Throwable throwable = null; - try { - future = this.connector.connect(inetSocketAddressWrapper); - - if (!future.get(this.connectTimeout, TimeUnit.MILLISECONDS)) { - log.error("connect to " - + SystemUtils.getRawAddress(inetSocketAddress) + ":" - + inetSocketAddress.getPort() + " fail"); - } else { - connected = true; - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } catch (ExecutionException e) { - throwable = e; - log.error( - "connect to " - + SystemUtils.getRawAddress(inetSocketAddress) - + ":" + inetSocketAddress.getPort() + " error", - e); - } catch (TimeoutException e) { - throwable = e; - log.error("connect to " - + SystemUtils.getRawAddress(inetSocketAddress) + ":" - + inetSocketAddress.getPort() + " timeout", e); - } catch (Exception e) { - throwable = e; - log.error( - "connect to " - + SystemUtils.getRawAddress(inetSocketAddress) - + ":" + inetSocketAddress.getPort() + " error", - e); - } - // If it is not connected,it will be added to waiting queue for - // reconnecting. - if (!connected) { - if (future != null) { - future.cancel(true); - } - // If we use failure mode, add a mock session at first - if (this.failureMode) { - this.connector.addSession(new ClosedMemcachedTCPSession( - inetSocketAddressWrapper)); - } - this.connector.addToWatingQueue( - new ReconnectRequest(inetSocketAddressWrapper, 0, - this.getHealSessionInterval())); - log.error( - "Connect to " - + SystemUtils.getRawAddress(inetSocketAddress) - + ":" + inetSocketAddress.getPort() + " fail", - throwable); - // throw new IOException(throwable); - } - } - } - - @SuppressWarnings("unchecked") - private final Object fetch0(final String key, final byte[] keyBytes, - final CommandType cmdType, final long timeout, - Transcoder transcoder) - throws InterruptedException, TimeoutException, MemcachedException { - final Command command = this.commandFactory.createGetCommand(key, - keyBytes, cmdType, this.transcoder); - this.latchWait(command, timeout, this.sendCommand(command)); - command.getIoBuffer().free(); // free buffer - this.checkException(command); - CachedData data = (CachedData) command.getResult(); - if (data == null) { - return null; - } - if (transcoder == null) { - transcoder = this.transcoder; - } - if (cmdType == CommandType.GETS_ONE) { - return new GetsResponse(data.getCas(), transcoder.decode(data)); - } else { - return transcoder.decode(data); - } - } - - private final void start0() throws IOException { - this.registerMBean(); - this.startConnector(); - MemcachedClientNameHolder.clear(); - } - - private final void startConnector() throws IOException { - if (this.shutdown) { - this.shutdown = false; - this.connector.start(); - this.memcachedHandler.start(); - if (AddrUtil.isEnableShutDownHook()) { - this.shutdownHookThread = new Thread() { - @Override - public void run() { - try { - XMemcachedClient.this.isHutdownHookCalled = true; - XMemcachedClient.this.shutdown(); - } catch (IOException e) { - log.error("Shutdown XMemcachedClient error", e); - } - } - }; - Runtime.getRuntime().addShutdownHook(this.shutdownHookThread); - } - } - } - - /** - * Set max queued noreply operations number - * - * @param maxQueuedNoReplyOperations - */ - void setMaxQueuedNoReplyOperations(int maxQueuedNoReplyOperations) { - if (maxQueuedNoReplyOperations <= 1) { - throw new IllegalArgumentException("maxQueuedNoReplyOperations<=1"); - } - this.maxQueuedNoReplyOperations = maxQueuedNoReplyOperations; - } - - @SuppressWarnings("unchecked") - private void buildConnector(MemcachedSessionLocator locator, - BufferAllocator bufferAllocator, Configuration configuration, - Map socketOptions, - CommandFactory commandFactory, Transcoder transcoder) { - if (locator == null) { - locator = new ArrayMemcachedSessionLocator(); - - } - if (bufferAllocator == null) { - bufferAllocator = new SimpleBufferAllocator(); - } - if (configuration == null) { - configuration = XMemcachedClientBuilder.getDefaultConfiguration(); - } - if (transcoder == null) { - transcoder = new SerializingTranscoder(); - } - if (commandFactory == null) { - commandFactory = new TextCommandFactory(); - } - if (this.name == null) { - this.name = "MemcachedClient-" - + Constants.MEMCACHED_CLIENT_COUNTER.getAndIncrement(); - MemcachedClientNameHolder.setName(this.name); - } - this.commandFactory = commandFactory; - ByteUtils.setProtocol(this.commandFactory.getProtocol()); - log.info("XMemcachedClient is using " - + this.commandFactory.getProtocol().name() + " protocol"); - this.commandFactory.setBufferAllocator(bufferAllocator); - this.shutdown = true; - this.transcoder = transcoder; - this.sessionLocator = locator; - this.connector = this.newConnector(bufferAllocator, configuration, - this.sessionLocator, this.commandFactory, - this.connectionPoolSize, this.maxQueuedNoReplyOperations); - this.memcachedHandler = new MemcachedHandler(this); - this.connector.setHandler(this.memcachedHandler); - this.connector.setCodecFactory(new MemcachedCodecFactory()); - this.connector.setSessionTimeout(-1); - this.connector.setSocketOptions(socketOptions); - if (this.isFailureMode()) { - log.info("XMemcachedClient in failure mode."); - } - this.connector.setFailureMode(this.failureMode); - this.sessionLocator.setFailureMode(this.failureMode); - } - - protected MemcachedConnector newConnector(BufferAllocator bufferAllocator, - Configuration configuration, - MemcachedSessionLocator memcachedSessionLocator, - CommandFactory commandFactory, int poolSize, - int maxQueuedNoReplyOperations) { - // make sure dispatch message thread count is zero - configuration.setDispatchMessageThreadCount(0); - return new MemcachedConnector(configuration, memcachedSessionLocator, - bufferAllocator, commandFactory, poolSize, - maxQueuedNoReplyOperations); - } - - private final void registerMBean() { - if (this.shutdown) { - XMemcachedMbeanServer.getInstance().registMBean(this, - this.getClass().getPackage().getName() + ":type=" - + this.getClass().getSimpleName() + "-" - + MemcachedClientNameHolder.getName()); - } - } - - public void setOptimizeGet(boolean optimizeGet) { - this.connector.setOptimizeGet(optimizeGet); - } - - /* - * (non-Javadoc) - * - * @see - * net.rubyeye.xmemcached.MemcachedClient#setBufferAllocator(net.rubyeye - * .xmemcached.buffer.BufferAllocator) - */ - public final void setBufferAllocator( - final BufferAllocator bufferAllocator) { - this.connector.setBufferAllocator(bufferAllocator); - } - - /** - * XMemcached Constructor. - * - * @param inetSocketAddress - * @param weight - * @throws IOException - */ - public XMemcachedClient(final InetSocketAddress inetSocketAddress, - int weight, CommandFactory cmdFactory) throws IOException { - super(); - if (inetSocketAddress == null) { - throw new IllegalArgumentException("Null InetSocketAddress"); - - } - if (cmdFactory == null) { - throw new IllegalArgumentException("Null command factory."); - } - if (weight <= 0) { - throw new IllegalArgumentException("weight<=0"); - } - this.buildConnector(new ArrayMemcachedSessionLocator(), - new SimpleBufferAllocator(), - XMemcachedClientBuilder.getDefaultConfiguration(), - XMemcachedClientBuilder.getDefaultSocketOptions(), cmdFactory, - new SerializingTranscoder()); - this.start0(); - this.connect(new InetSocketAddressWrapper(inetSocketAddress, - this.serverOrderCount.incrementAndGet(), weight, null)); - } - - public XMemcachedClient(final InetSocketAddress inetSocketAddress, - int weight) throws IOException { - this(inetSocketAddress, weight, new TextCommandFactory()); - } - - public XMemcachedClient(final InetSocketAddress inetSocketAddress) - throws IOException { - this(inetSocketAddress, 1); - } - - public XMemcachedClient() throws IOException { - super(); - this.buildConnector(new ArrayMemcachedSessionLocator(), - new SimpleBufferAllocator(), - XMemcachedClientBuilder.getDefaultConfiguration(), - XMemcachedClientBuilder.getDefaultSocketOptions(), - new TextCommandFactory(), new SerializingTranscoder()); - this.start0(); - } - - /** - * XMemcachedClient constructor.Every server's weight is one by default. You - * should not new client instance by this method, use MemcachedClientBuilder - * instead. - * - * @param locator - * @param allocator - * @param conf - * @param commandFactory - * @param transcoder - * @param addressList - * @param stateListeners - * @throws IOException - */ - @SuppressWarnings("unchecked") - public XMemcachedClient(MemcachedSessionLocator locator, - BufferAllocator allocator, Configuration conf, - Map socketOptions, - CommandFactory commandFactory, Transcoder transcoder, - Map addressMap, - List stateListeners, - Map map, int poolSize, - long connectTimeout, String name, boolean failureMode) - throws IOException { - super(); - this.setConnectTimeout(connectTimeout); - this.setFailureMode(failureMode); - this.setName(name); - this.optimiezeSetReadThreadCount(conf, - addressMap == null ? 0 : addressMap.size()); - this.buildConnector(locator, allocator, conf, socketOptions, - commandFactory, transcoder); - if (stateListeners != null) { - for (MemcachedClientStateListener stateListener : stateListeners) { - this.addStateListener(stateListener); - } - } - this.setAuthInfoMap(map); - this.setConnectionPoolSize(poolSize); - this.start0(); - if (addressMap != null) { - for (Map.Entry entry : addressMap - .entrySet()) { - final InetSocketAddress mainNodeAddr = entry.getKey(); - final InetSocketAddress standbyNodeAddr = entry.getValue(); - this.connect(new InetSocketAddressWrapper(mainNodeAddr, - this.serverOrderCount.incrementAndGet(), 1, null)); - if (standbyNodeAddr != null) { - this.connect(new InetSocketAddressWrapper(standbyNodeAddr, - this.serverOrderCount.incrementAndGet(), 1, - mainNodeAddr)); - } - } - } - } - - /** - * XMemcachedClient constructor. - * - * @param locator - * @param allocator - * @param conf - * @param commandFactory - * @param transcoder - * @param addressList - * @param weights - * @param stateListeners - * weight array for address list - * @throws IOException - */ - @SuppressWarnings("unchecked") - XMemcachedClient(MemcachedSessionLocator locator, BufferAllocator allocator, - Configuration conf, Map socketOptions, - CommandFactory commandFactory, Transcoder transcoder, - Map addressMap, int[] weights, - List stateListeners, - Map infoMap, int poolSize, - long connectTimeout, final String name, boolean failureMode) - throws IOException { - super(); - this.setConnectTimeout(connectTimeout); - this.setFailureMode(failureMode); - this.setName(name); - if (weights == null && addressMap != null) { - throw new IllegalArgumentException("Null weights"); - } - if (weights != null && addressMap == null) { - throw new IllegalArgumentException("Null addressList"); - } - - if (weights != null) { - for (int weight : weights) { - if (weight <= 0) { - throw new IllegalArgumentException("Some weights<=0"); - } - } - } - if (weights != null && addressMap != null - && weights.length < addressMap.size()) { - throw new IllegalArgumentException( - "weights.length is less than addressList.size()"); - } - this.optimiezeSetReadThreadCount(conf, - addressMap == null ? 0 : addressMap.size()); - this.buildConnector(locator, allocator, conf, socketOptions, - commandFactory, transcoder); - if (stateListeners != null) { - for (MemcachedClientStateListener stateListener : stateListeners) { - this.addStateListener(stateListener); - } - } - this.setAuthInfoMap(infoMap); - this.setConnectionPoolSize(poolSize); - this.start0(); - if (addressMap != null && weights != null) { - int i = 0; - for (Map.Entry entry : addressMap - .entrySet()) { - final InetSocketAddress mainNodeAddr = entry.getKey(); - final InetSocketAddress standbyNodeAddr = entry.getValue(); - this.connect(new InetSocketAddressWrapper(mainNodeAddr, - this.serverOrderCount.incrementAndGet(), weights[i], - null)); - if (standbyNodeAddr != null) { - this.connect(new InetSocketAddressWrapper(standbyNodeAddr, - this.serverOrderCount.incrementAndGet(), weights[i], - mainNodeAddr)); - } - i++; - } - } - } - - private final void optimiezeSetReadThreadCount(Configuration conf, - int addressCount) { - if (conf != null && addressCount > 1) { - if (!this.isWindowsPlatform() - && conf.getReadThreadCount() == DEFAULT_READ_THREAD_COUNT) { - int threadCount = SystemUtils.getSystemThreadCount(); - conf.setReadThreadCount(addressCount > threadCount - ? threadCount - : addressCount); - } - } - } - - private final boolean isWindowsPlatform() { - String osName = System.getProperty("os.name"); - if (osName != null && osName.toLowerCase().indexOf("windows") >= 0) { - return true; - } else { - return false; - } - } - - /** - * XMemcached Constructor.Every server's weight is one by default. - * - * @param addressList - * @throws IOException - */ - public XMemcachedClient(List addressList) - throws IOException { - this(addressList, new TextCommandFactory()); - } - - /** - * XMemcached Constructor.Every server's weight is one by default. - * - * @param cmdFactory - * command factory - * @param addressList - * memcached server socket address list. - * @throws IOException - */ - public XMemcachedClient(List addressList, - CommandFactory cmdFactory) throws IOException { - super(); - if (cmdFactory == null) { - throw new IllegalArgumentException("Null command factory."); - } - if (addressList == null || addressList.isEmpty()) { - throw new IllegalArgumentException("Empty address list"); - } - BufferAllocator simpleBufferAllocator = new SimpleBufferAllocator(); - this.buildConnector(new ArrayMemcachedSessionLocator(), - simpleBufferAllocator, - XMemcachedClientBuilder.getDefaultConfiguration(), - XMemcachedClientBuilder.getDefaultSocketOptions(), cmdFactory, - new SerializingTranscoder()); - this.start0(); - for (InetSocketAddress inetSocketAddress : addressList) { - this.connect(new InetSocketAddressWrapper(inetSocketAddress, - this.serverOrderCount.incrementAndGet(), 1, null)); - - } - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#get(java.lang.String, long, - * net.rubyeye.xmemcached.transcoders.Transcoder) - */ - @SuppressWarnings("unchecked") - public final T get(final String key, final long timeout, - final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException { - return (T) this.get0(key, timeout, CommandType.GET_ONE, transcoder); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#get(java.lang.String, long) - */ - @SuppressWarnings("unchecked") - public final T get(final String key, final long timeout) - throws TimeoutException, InterruptedException, MemcachedException { - return (T) this.get(key, timeout, this.transcoder); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#get(java.lang.String, - * net.rubyeye.xmemcached.transcoders.Transcoder) - */ - public final T get(final String key, final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException { - return this.get(key, this.opTimeout, transcoder); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#get(java.lang.String) - */ - @SuppressWarnings("unchecked") - public final T get(final String key) - throws TimeoutException, InterruptedException, MemcachedException { - return (T) this.get(key, this.opTimeout); - } - - private Object get0(String key, final long timeout, - final CommandType cmdType, final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException { - key = this.preProcessKey(key); - byte[] keyBytes = ByteUtils.getBytes(key); - ByteUtils.checkKey(keyBytes); - return this.fetch0(key, keyBytes, cmdType, timeout, transcoder); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#gets(java.lang.String, long, - * net.rubyeye.xmemcached.transcoders.Transcoder) - */ - @SuppressWarnings("unchecked") - public final GetsResponse gets(final String key, final long timeout, - final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException { - return (GetsResponse) this.get0(key, timeout, CommandType.GETS_ONE, - transcoder); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#gets(java.lang.String) - */ - public final GetsResponse gets(final String key) - throws TimeoutException, InterruptedException, MemcachedException { - return this.gets(key, this.opTimeout); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#gets(java.lang.String, long) - */ - @SuppressWarnings("unchecked") - public final GetsResponse gets(final String key, final long timeout) - throws TimeoutException, InterruptedException, MemcachedException { - return this.gets(key, timeout, this.transcoder); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#gets(java.lang.String, - * net.rubyeye.xmemcached.transcoders.Transcoder) - */ - @SuppressWarnings("unchecked") - public final GetsResponse gets(final String key, - final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException { - return this.gets(key, this.opTimeout, transcoder); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#get(java.util.Collection, - * long, net.rubyeye.xmemcached.transcoders.Transcoder) - */ - public final Map get(final Collection keyCollections, - final long timeout, final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException { - return this.getMulti0(keyCollections, timeout, CommandType.GET_MANY, - transcoder); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#get(java.util.Collection, - * net.rubyeye.xmemcached.transcoders.Transcoder) - */ - public final Map get(final Collection keyCollections, - final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException { - return this.getMulti0(keyCollections, this.opTimeout, - CommandType.GET_MANY, transcoder); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#get(java.util.Collection) - */ - public final Map get(final Collection keyCollections) - throws TimeoutException, InterruptedException, MemcachedException { - return this.get(keyCollections, this.opTimeout); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#get(java.util.Collection, - * long) - */ - @SuppressWarnings("unchecked") - public final Map get(final Collection keyCollections, - final long timeout) - throws TimeoutException, InterruptedException, MemcachedException { - return this.get(keyCollections, timeout, this.transcoder); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#gets(java.util.Collection, - * long, net.rubyeye.xmemcached.transcoders.Transcoder) - */ - @SuppressWarnings("unchecked") - public final Map> gets( - final Collection keyCollections, final long timeout, - final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException { - return (Map>) this.getMulti0(keyCollections, - timeout, CommandType.GETS_MANY, transcoder); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#gets(java.util.Collection) - */ - public final Map> gets( - final Collection keyCollections) - throws TimeoutException, InterruptedException, MemcachedException { - return this.gets(keyCollections, this.opTimeout); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#gets(java.util.Collection, - * long) - */ - @SuppressWarnings("unchecked") - public final Map> gets( - final Collection keyCollections, final long timeout) - throws TimeoutException, InterruptedException, MemcachedException { - return this.gets(keyCollections, timeout, this.transcoder); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#gets(java.util.Collection, - * net.rubyeye.xmemcached.transcoders.Transcoder) - */ - public final Map> gets( - final Collection keyCollections, - final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException { - return this.gets(keyCollections, this.opTimeout, transcoder); - } - - private final Map getMulti0(final Collection keys, - final long timeout, final CommandType cmdType, - final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException { - if (keys == null || keys.size() == 0) { - return null; - } - Collection keyCollections = new ArrayList(keys.size()); - for (String key : keys) { - keyCollections.add(this.preProcessKey(key)); - } - final CountDownLatch latch; - final List commands; - if (this.connector.getSessionSet().size() <= 1) { - commands = new ArrayList(1); - latch = new CountDownLatch(1); - commands.add(this.sendGetMultiCommand(keyCollections, latch, - cmdType, transcoder)); - - } else { - Collection> catalogKeys = this - .catalogKeys(keyCollections); - commands = new ArrayList(catalogKeys.size()); - latch = new CountDownLatch(catalogKeys.size()); - for (List catalogKeyCollection : catalogKeys) { - commands.add(this.sendGetMultiCommand(catalogKeyCollection, - latch, cmdType, transcoder)); - } - } - if (!latch.await(timeout, TimeUnit.MILLISECONDS)) { - for (Command getCmd : commands) { - getCmd.cancel(); - } - throw new TimeoutException("Timed out waiting for operation"); - } - return this.reduceResult(cmdType, transcoder, commands); - } - - @SuppressWarnings("unchecked") - private Map reduceResult(final CommandType cmdType, - final Transcoder transcoder, final List commands) - throws MemcachedException, InterruptedException, TimeoutException { - final Map result = new HashMap(commands.size()); - for (Command getCmd : commands) { - getCmd.getIoBuffer().free(); - this.checkException(getCmd); - Map map = (Map) getCmd - .getResult(); - if (cmdType == CommandType.GET_MANY) { - Iterator> it = map.entrySet() - .iterator(); - while (it.hasNext()) { - Map.Entry entry = it.next(); - String decodeKey = this.decodeKey(entry.getKey()); - if (decodeKey != null) { - result.put(decodeKey, - transcoder.decode(entry.getValue())); - } - } - - } else { - Iterator> it = map.entrySet() - .iterator(); - while (it.hasNext()) { - Map.Entry entry = it.next(); - GetsResponse getsResponse = new GetsResponse( - entry.getValue().getCas(), - transcoder.decode(entry.getValue())); - String decodeKey = this.decodeKey(entry.getKey()); - if (decodeKey != null) { - result.put(decodeKey, (T) getsResponse); - } - } - - } - - } - return result; - } - - /** - * Hash key to servers - * - * @param keyCollections - * @return - */ - private final Collection> catalogKeys( - final Collection keyCollections) { - final Map> catalogMap = new HashMap>(); - - for (String key : keyCollections) { - Session index = this.sessionLocator.getSessionByKey(key); - List tmpKeys = catalogMap.get(index); - if (tmpKeys == null) { - tmpKeys = new ArrayList(10); - catalogMap.put(index, tmpKeys); - } - tmpKeys.add(key); - } - - Collection> catalogKeys = catalogMap.values(); - return catalogKeys; - } - - private final Command sendGetMultiCommand(final Collection keys, - final CountDownLatch latch, final CommandType cmdType, - final Transcoder transcoder) - throws InterruptedException, TimeoutException, MemcachedException { - final Command command = this.commandFactory.createGetMultiCommand(keys, - latch, cmdType, transcoder); - this.sendCommand(command); - return command; - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#set(java.lang.String, int, T, - * net.rubyeye.xmemcached.transcoders.Transcoder, long) - */ - public final boolean set(String key, final int exp, final T value, - final Transcoder transcoder, final long timeout) - throws TimeoutException, InterruptedException, MemcachedException { - key = this.preProcessKey(key); - byte[] keyBytes = this.checkStoreArguments(key, exp, value); - return this.sendStoreCommand(this.commandFactory.createSetCommand(key, - keyBytes, exp, value, false, transcoder), timeout); - } - - @SuppressWarnings("unchecked") - public void setWithNoReply(String key, int exp, Object value) - throws InterruptedException, MemcachedException { - this.setWithNoReply(key, exp, value, this.transcoder); - } - - public void setWithNoReply(String key, int exp, T value, - Transcoder transcoder) - throws InterruptedException, MemcachedException { - key = this.preProcessKey(key); - byte[] keyBytes = this.checkStoreArguments(key, exp, value); - try { - this.sendStoreCommand(this.commandFactory.createSetCommand(key, - keyBytes, exp, value, true, transcoder), this.opTimeout); - } catch (TimeoutException e) { - throw new MemcachedException(e); - } - } - - private final byte[] checkStoreArguments(final String key, - final int exp, final T value) { - byte[] keyBytes = ByteUtils.getBytes(key); - ByteUtils.checkKey(keyBytes); - if (value == null) { - throw new IllegalArgumentException("value could not be null"); - } - if (exp < 0) { - throw new IllegalArgumentException( - "Expire time must be greater than or equal to 0"); - } - return keyBytes; - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#set(java.lang.String, int, - * java.lang.Object) - */ - public final boolean set(final String key, final int exp, - final Object value) - throws TimeoutException, InterruptedException, MemcachedException { - return this.set(key, exp, value, this.opTimeout); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#set(java.lang.String, int, - * java.lang.Object, long) - */ - @SuppressWarnings("unchecked") - public final boolean set(final String key, final int exp, - final Object value, final long timeout) - throws TimeoutException, InterruptedException, MemcachedException { - return this.set(key, exp, value, this.transcoder, timeout); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#set(java.lang.String, int, T, - * net.rubyeye.xmemcached.transcoders.Transcoder) - */ - public final boolean set(final String key, final int exp, final T value, - final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException { - return this.set(key, exp, value, transcoder, this.opTimeout); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#add(java.lang.String, int, T, - * net.rubyeye.xmemcached.transcoders.Transcoder, long) - */ - public final boolean add(String key, final int exp, final T value, - final Transcoder transcoder, final long timeout) - throws TimeoutException, InterruptedException, MemcachedException { - key = this.preProcessKey(key); - return this.add0(key, exp, value, transcoder, timeout); - } - - private boolean add0(String key, int exp, T value, - Transcoder transcoder, long timeout) - throws InterruptedException, TimeoutException, MemcachedException { - byte[] keyBytes = this.checkStoreArguments(key, exp, value); - return this.sendStoreCommand(this.commandFactory.createAddCommand(key, - keyBytes, exp, value, false, transcoder), timeout); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#add(java.lang.String, int, - * java.lang.Object) - */ - public final boolean add(final String key, final int exp, - final Object value) - throws TimeoutException, InterruptedException, MemcachedException { - return this.add(key, exp, value, this.opTimeout); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#add(java.lang.String, int, - * java.lang.Object, long) - */ - @SuppressWarnings("unchecked") - public final boolean add(final String key, final int exp, - final Object value, final long timeout) - throws TimeoutException, InterruptedException, MemcachedException { - return this.add(key, exp, value, this.transcoder, timeout); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#add(java.lang.String, int, T, - * net.rubyeye.xmemcached.transcoders.Transcoder) - */ - public final boolean add(final String key, final int exp, final T value, - final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException { - return this.add(key, exp, value, transcoder, this.opTimeout); - } - - @SuppressWarnings("unchecked") - public void addWithNoReply(String key, int exp, Object value) - throws InterruptedException, MemcachedException { - this.addWithNoReply(key, exp, value, this.transcoder); - - } - - public void addWithNoReply(String key, int exp, T value, - Transcoder transcoder) - throws InterruptedException, MemcachedException { - key = this.preProcessKey(key); - byte[] keyBytes = this.checkStoreArguments(key, exp, value); - try { - this.sendStoreCommand(this.commandFactory.createAddCommand(key, - keyBytes, exp, value, true, transcoder), this.opTimeout); - } catch (TimeoutException e) { - throw new MemcachedException(e); - } - - } - - @SuppressWarnings("unchecked") - public void replaceWithNoReply(String key, int exp, Object value) - throws InterruptedException, MemcachedException { - this.replaceWithNoReply(key, exp, value, this.transcoder); - - } - - public void replaceWithNoReply(String key, int exp, T value, - Transcoder transcoder) - throws InterruptedException, MemcachedException { - key = this.preProcessKey(key); - byte[] keyBytes = this.checkStoreArguments(key, exp, value); - try { - this.sendStoreCommand(this.commandFactory.createReplaceCommand(key, - keyBytes, exp, value, true, transcoder), this.opTimeout); - } catch (TimeoutException e) { - throw new MemcachedException(e); - } - - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#replace(java.lang.String, - * int, T, net.rubyeye.xmemcached.transcoders.Transcoder, long) - */ - public final boolean replace(String key, final int exp, final T value, - final Transcoder transcoder, final long timeout) - throws TimeoutException, InterruptedException, MemcachedException { - key = this.preProcessKey(key); - byte[] keyBytes = this.checkStoreArguments(key, exp, value); - return this.sendStoreCommand(this.commandFactory.createReplaceCommand( - key, keyBytes, exp, value, false, transcoder), timeout); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#replace(java.lang.String, - * int, java.lang.Object) - */ - public final boolean replace(final String key, final int exp, - final Object value) - throws TimeoutException, InterruptedException, MemcachedException { - return this.replace(key, exp, value, this.opTimeout); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#replace(java.lang.String, - * int, java.lang.Object, long) - */ - @SuppressWarnings("unchecked") - public final boolean replace(final String key, final int exp, - final Object value, final long timeout) - throws TimeoutException, InterruptedException, MemcachedException { - return this.replace(key, exp, value, this.transcoder, timeout); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#replace(java.lang.String, - * int, T, net.rubyeye.xmemcached.transcoders.Transcoder) - */ - public final boolean replace(final String key, final int exp, - final T value, final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException { - return this.replace(key, exp, value, transcoder, this.opTimeout); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#append(java.lang.String, - * java.lang.Object) - */ - public final boolean append(final String key, final Object value) - throws TimeoutException, InterruptedException, MemcachedException { - return this.append(key, value, this.opTimeout); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#append(java.lang.String, - * java.lang.Object, long) - */ - public final boolean append(String key, final Object value, - final long timeout) - throws TimeoutException, InterruptedException, MemcachedException { - key = this.preProcessKey(key); - byte[] keyBytes = this.checkStoreArguments(key, 0, value); - return this.sendStoreCommand(this.commandFactory.createAppendCommand( - key, keyBytes, value, false, this.transcoder), timeout); - } - - public void appendWithNoReply(String key, Object value) - throws InterruptedException, MemcachedException { - key = this.preProcessKey(key); - byte[] keyBytes = this.checkStoreArguments(key, 0, value); - try { - this.sendStoreCommand(this.commandFactory.createAppendCommand(key, - keyBytes, value, true, this.transcoder), this.opTimeout); - } catch (TimeoutException e) { - throw new MemcachedException(e); - } - - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#prepend(java.lang.String, - * java.lang.Object) - */ - public final boolean prepend(final String key, final Object value) - throws TimeoutException, InterruptedException, MemcachedException { - return this.prepend(key, value, this.opTimeout); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#prepend(java.lang.String, - * java.lang.Object, long) - */ - public final boolean prepend(String key, final Object value, - final long timeout) - throws TimeoutException, InterruptedException, MemcachedException { - key = this.preProcessKey(key); - byte[] keyBytes = this.checkStoreArguments(key, 0, value); - return this.sendStoreCommand(this.commandFactory.createPrependCommand( - key, keyBytes, value, false, this.transcoder), timeout); - } - - public void prependWithNoReply(String key, Object value) - throws InterruptedException, MemcachedException { - key = this.preProcessKey(key); - byte[] keyBytes = this.checkStoreArguments(key, 0, value); - try { - this.sendStoreCommand(this.commandFactory.createPrependCommand(key, - keyBytes, value, true, this.transcoder), this.opTimeout); - } catch (TimeoutException e) { - throw new MemcachedException(e); - } - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#cas(java.lang.String, int, - * java.lang.Object, long) - */ - public final boolean cas(final String key, final int exp, - final Object value, final long cas) - throws TimeoutException, InterruptedException, MemcachedException { - return this.cas(key, exp, value, this.opTimeout, cas); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#cas(java.lang.String, int, T, - * net.rubyeye.xmemcached.transcoders.Transcoder, long, long) - */ - public final boolean cas(String key, final int exp, final T value, - final Transcoder transcoder, final long timeout, final long cas) - throws TimeoutException, InterruptedException, MemcachedException { - key = this.preProcessKey(key); - byte[] keyBytes = this.checkStoreArguments(key, 0, value); - return this.sendStoreCommand(this.commandFactory.createCASCommand(key, - keyBytes, exp, value, cas, false, transcoder), timeout); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#cas(java.lang.String, int, - * java.lang.Object, long, long) - */ - @SuppressWarnings("unchecked") - public final boolean cas(final String key, final int exp, - final Object value, final long timeout, final long cas) - throws TimeoutException, InterruptedException, MemcachedException { - return this.cas(key, exp, value, this.transcoder, timeout, cas); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#cas(java.lang.String, int, T, - * net.rubyeye.xmemcached.transcoders.Transcoder, long) - */ - public final boolean cas(final String key, final int exp, final T value, - final Transcoder transcoder, final long cas) - throws TimeoutException, InterruptedException, MemcachedException { - return this.cas(key, exp, value, transcoder, this.opTimeout, cas); - } - - private final boolean cas0(final String key, final int exp, - GetsResponse getsResponse, final CASOperation operation, - final Transcoder transcoder, byte[] keyBytes, boolean noreply) - throws TimeoutException, InterruptedException, MemcachedException { - if (operation == null) { - throw new IllegalArgumentException( - "CASOperation could not be null"); - } - if (operation.getMaxTries() < 0) { - throw new IllegalArgumentException( - "max tries must be greater than 0"); - } - int tryCount = 0; - GetsResponse result = getsResponse; - if (result == null) { - throw new NoValueException("Null GetsResponse for key=" + key); - } - while (tryCount <= operation.getMaxTries() - && result != null && !this - .sendStoreCommand( - this.commandFactory.createCASCommand(key, - keyBytes, exp, - operation.getNewValue(result.getCas(), - result.getValue()), - result.getCas(), noreply, transcoder), - this.opTimeout) - && !noreply) { - tryCount++; - result = this.gets0(key, keyBytes, transcoder); - if (result == null) { - throw new NoValueException( - "could not gets the value for Key=" + key + " for cas"); - } - if (tryCount > operation.getMaxTries()) { - throw new TimeoutException("CAS try times is greater than max"); - } - } - return true; - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#cas(java.lang.String, int, - * net.rubyeye.xmemcached.CASOperation, - * net.rubyeye.xmemcached.transcoders.Transcoder) - */ - public final boolean cas(String key, final int exp, - final CASOperation operation, final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException { - key = this.preProcessKey(key); - byte[] keyBytes = ByteUtils.getBytes(key); - ByteUtils.checkKey(keyBytes); - GetsResponse result = this.gets0(key, keyBytes, transcoder); - return this.cas0(key, exp, result, operation, transcoder, keyBytes, - false); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#cas(java.lang.String, int, - * net.rubyeye.xmemcached.GetsResponse, net.rubyeye.xmemcached.CASOperation, - * net.rubyeye.xmemcached.transcoders.Transcoder) - */ - public final boolean cas(String key, final int exp, - GetsResponse getsReponse, final CASOperation operation, - final Transcoder transcoder) - throws TimeoutException, InterruptedException, MemcachedException { - key = this.preProcessKey(key); - byte[] keyBytes = ByteUtils.getBytes(key); - ByteUtils.checkKey(keyBytes); - return this.cas0(key, exp, getsReponse, operation, transcoder, keyBytes, - false); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#cas(java.lang.String, int, - * net.rubyeye.xmemcached.GetsResponse, net.rubyeye.xmemcached.CASOperation) - */ - @SuppressWarnings("unchecked") - public final boolean cas(final String key, final int exp, - GetsResponse getsReponse, final CASOperation operation) - throws TimeoutException, InterruptedException, MemcachedException { - - return this.cas(key, exp, getsReponse, operation, this.transcoder); - } - - public void casWithNoReply(String key, CASOperation operation) - throws TimeoutException, InterruptedException, MemcachedException { - this.casWithNoReply(key, 0, operation); - } - - public void casWithNoReply(String key, GetsResponse getsResponse, - CASOperation operation) - throws TimeoutException, InterruptedException, MemcachedException { - this.casWithNoReply(key, 0, getsResponse, operation); - - } - - @SuppressWarnings("unchecked") - public void casWithNoReply(String key, int exp, - CASOperation operation) - throws TimeoutException, InterruptedException, MemcachedException { - key = this.preProcessKey(key); - byte[] keyBytes = ByteUtils.getBytes(key); - GetsResponse result = this.gets0(key, keyBytes, this.transcoder); - this.casWithNoReply(key, exp, result, operation); - - } - - @SuppressWarnings("unchecked") - public void casWithNoReply(String key, int exp, - GetsResponse getsReponse, CASOperation operation) - throws TimeoutException, InterruptedException, MemcachedException { - key = this.preProcessKey(key); - byte[] keyBytes = ByteUtils.getBytes(key); - ByteUtils.checkKey(keyBytes); - this.cas0(key, exp, getsReponse, operation, this.transcoder, keyBytes, - true); - - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#cas(java.lang.String, - * net.rubyeye.xmemcached.GetsResponse, net.rubyeye.xmemcached.CASOperation) - */ - public final boolean cas(final String key, GetsResponse getsReponse, - final CASOperation operation) - throws TimeoutException, InterruptedException, MemcachedException { - return this.cas(key, 0, getsReponse, operation); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#cas(java.lang.String, int, - * net.rubyeye.xmemcached.CASOperation) - */ - @SuppressWarnings("unchecked") - public final boolean cas(final String key, final int exp, - final CASOperation operation) - throws TimeoutException, InterruptedException, MemcachedException { - return this.cas(key, exp, operation, this.transcoder); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#cas(java.lang.String, - * net.rubyeye.xmemcached.CASOperation) - */ - public final boolean cas(final String key, - final CASOperation operation) - throws TimeoutException, InterruptedException, MemcachedException { - return this.cas(key, 0, operation); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#delete(java.lang.String, int) - */ - public final boolean delete(final String key, final int time) - throws TimeoutException, InterruptedException, MemcachedException { - return this.delete0(key, time, 0, false, this.opTimeout); - } - - public boolean delete(String key, long opTimeout) - throws TimeoutException, InterruptedException, MemcachedException { - return this.delete0(key, 0, 0, false, opTimeout); - } - - public boolean delete(String key, long cas, long opTimeout) - throws TimeoutException, InterruptedException, MemcachedException { - return this.delete0(key, 0, cas, false, opTimeout); - } - - /** - * Delete key's data item from memcached.This method doesn't wait for reply - * - * @param key - * @param time - * @throws InterruptedException - * @throws MemcachedException - */ - public final void deleteWithNoReply(final String key, final int time) - throws InterruptedException, MemcachedException { - try { - this.delete0(key, time, 0, true, this.opTimeout); - } catch (TimeoutException e) { - throw new MemcachedException(e); - } - } - - public final void deleteWithNoReply(final String key) - throws InterruptedException, MemcachedException { - this.deleteWithNoReply(key, 0); - } - - private boolean delete0(String key, final int time, long cas, - boolean noreply, long opTimeout) - throws MemcachedException, InterruptedException, TimeoutException { - key = this.preProcessKey(key); - final byte[] keyBytes = ByteUtils.getBytes(key); - ByteUtils.checkKey(keyBytes); - final Command command = this.commandFactory.createDeleteCommand(key, - keyBytes, time, cas, noreply); - final Session session = this.sendCommand(command); - if (!command.isNoreply()) { - this.latchWait(command, opTimeout, session); - command.getIoBuffer().free(); - this.checkException(command); - if (command.getResult() == null) { - throw new MemcachedException( - "Operation fail,may be caused by networking or timeout"); - } - } else { - return false; - } - return (Boolean) command.getResult(); - } - - protected void checkException(final Command command) - throws MemcachedException { - if (command.getException() != null) { - if (command.getException() instanceof MemcachedException) { - throw (MemcachedException) command.getException(); - } else { - throw new MemcachedException(command.getException()); - } - } - } - - public boolean touch(String key, int exp, long opTimeout) - throws TimeoutException, InterruptedException, MemcachedException { - key = this.preProcessKey(key); - final byte[] keyBytes = ByteUtils.getBytes(key); - ByteUtils.checkKey(keyBytes); - CountDownLatch latch = new CountDownLatch(1); - final Command command = this.commandFactory.createTouchCommand(key, - keyBytes, latch, exp, false); - this.latchWait(command, opTimeout, this.sendCommand(command)); - command.getIoBuffer().free(); - this.checkException(command); - if (command.getResult() == null) { - throw new MemcachedException( - "Operation fail,may be caused by networking or timeout"); - } - return (Boolean) command.getResult(); - } - - public boolean touch(String key, int exp) - throws TimeoutException, InterruptedException, MemcachedException { - return this.touch(key, exp, this.opTimeout); - } - - @SuppressWarnings("unchecked") - public T getAndTouch(String key, int newExp, long opTimeout) - throws TimeoutException, InterruptedException, MemcachedException { - key = this.preProcessKey(key); - final byte[] keyBytes = ByteUtils.getBytes(key); - ByteUtils.checkKey(keyBytes); - CountDownLatch latch = new CountDownLatch(1); - final Command command = this.commandFactory - .createGetAndTouchCommand(key, keyBytes, latch, newExp, false); - this.latchWait(command, opTimeout, this.sendCommand(command)); - command.getIoBuffer().free(); - this.checkException(command); - CachedData data = (CachedData) command.getResult(); - if (data == null) { - return null; - } - return (T) this.transcoder.decode(data); - } - - @SuppressWarnings("unchecked") - public T getAndTouch(String key, int newExp) - throws TimeoutException, InterruptedException, MemcachedException { - return (T) this.getAndTouch(key, newExp, this.opTimeout); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#incr(java.lang.String, int) - */ - public final long incr(String key, final long delta) - throws TimeoutException, InterruptedException, MemcachedException { - key = this.preProcessKey(key); - return this.sendIncrOrDecrCommand(key, delta, 0, CommandType.INCR, - false, this.opTimeout, 0); - } - - public long incr(String key, long delta, long initValue) - throws TimeoutException, InterruptedException, MemcachedException { - key = this.preProcessKey(key); - return this.sendIncrOrDecrCommand(key, delta, initValue, - CommandType.INCR, false, this.opTimeout, 0); - } - - public long incr(String key, long delta, long initValue, long timeout) - throws TimeoutException, InterruptedException, MemcachedException { - key = this.preProcessKey(key); - return this.sendIncrOrDecrCommand(key, delta, initValue, - CommandType.INCR, false, timeout, 0); - } - - public long incr(String key, long delta, long initValue, long timeout, - int exp) - throws TimeoutException, InterruptedException, MemcachedException { - key = this.preProcessKey(key); - return this.sendIncrOrDecrCommand(key, delta, initValue, - CommandType.INCR, false, timeout, exp); - } - - public final void incrWithNoReply(String key, long delta) - throws InterruptedException, MemcachedException { - key = this.preProcessKey(key); - try { - this.sendIncrOrDecrCommand(key, delta, 0, CommandType.INCR, true, - this.opTimeout, 0); - } catch (TimeoutException e) { - throw new MemcachedException(e); - } - } - - public final void decrWithNoReply(String key, final long delta) - throws InterruptedException, MemcachedException { - key = this.preProcessKey(key); - try { - this.sendIncrOrDecrCommand(key, delta, 0, CommandType.DECR, true, - this.opTimeout, 0); - } catch (TimeoutException e) { - throw new MemcachedException(e); - } - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#decr(java.lang.String, int) - */ - public final long decr(String key, final long delta) - throws TimeoutException, InterruptedException, MemcachedException { - key = this.preProcessKey(key); - return this.sendIncrOrDecrCommand(key, delta, 0, CommandType.DECR, - false, this.opTimeout, 0); - } - - public long decr(String key, long delta, long initValue) - throws TimeoutException, InterruptedException, MemcachedException { - key = this.preProcessKey(key); - return this.sendIncrOrDecrCommand(key, delta, initValue, - CommandType.DECR, false, this.opTimeout, 0); - } - - public long decr(String key, long delta, long initValue, long timeout) - throws TimeoutException, InterruptedException, MemcachedException { - key = this.preProcessKey(key); - return this.sendIncrOrDecrCommand(key, delta, initValue, - CommandType.DECR, false, timeout, 0); - } - - public long decr(String key, long delta, long initValue, long timeout, - int exp) - throws TimeoutException, InterruptedException, MemcachedException { - key = this.preProcessKey(key); - return this.sendIncrOrDecrCommand(key, delta, initValue, - CommandType.DECR, false, timeout, exp); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#flushAll() - */ - public final void flushAll() - throws TimeoutException, InterruptedException, MemcachedException { - this.flushAll(this.opTimeout); - } - - public void flushAllWithNoReply() - throws InterruptedException, MemcachedException { - try { - this.flushAllMemcachedServers(this.opTimeout, true, 0); - } catch (TimeoutException e) { - throw new MemcachedException(e); - } - } - - public void flushAllWithNoReply(int exptime) - throws InterruptedException, MemcachedException { - try { - this.flushAllMemcachedServers(this.opTimeout, true, exptime); - } catch (TimeoutException e) { - throw new MemcachedException(e); - } - } - - public void flushAllWithNoReply(InetSocketAddress address) - throws MemcachedException, InterruptedException { - try { - this.flushSpecialMemcachedServer(address, this.opTimeout, true, 0); - } catch (TimeoutException e) { - throw new MemcachedException(e); - } - } - - public void flushAllWithNoReply(InetSocketAddress address, int exptime) - throws MemcachedException, InterruptedException { - try { - this.flushSpecialMemcachedServer(address, this.opTimeout, true, - exptime); - } catch (TimeoutException e) { - throw new MemcachedException(e); - } - } - - public final void flushAll(int exptime, long timeout) - throws TimeoutException, InterruptedException, MemcachedException { - this.flushAllMemcachedServers(timeout, false, exptime); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#flushAll(long) - */ - public final void flushAll(long timeout) - throws TimeoutException, InterruptedException, MemcachedException { - this.flushAllMemcachedServers(timeout, false, 0); - } - - private void flushAllMemcachedServers(long timeout, boolean noreply, - int exptime) - throws MemcachedException, InterruptedException, TimeoutException { - final Collection sessions = this.connector.getSessionSet(); - CountDownLatch latch = new CountDownLatch(sessions.size()); - List commands = new ArrayList(sessions.size()); - for (Session session : sessions) { - if (session != null && !session.isClosed()) { - Command command = this.commandFactory - .createFlushAllCommand(latch, exptime, noreply); - - session.write(command); - } else { - latch.countDown(); - } - } - if (!noreply) { - if (!latch.await(timeout, TimeUnit.MILLISECONDS)) { - for (Command cmd : commands) { - cmd.cancel(); - } - throw new TimeoutException("Timed out waiting for operation"); - } - } - } - - public void setLoggingLevelVerbosity(InetSocketAddress address, int level) - throws TimeoutException, InterruptedException, MemcachedException { - this.setMemcachedLoggingLevel(address, level, false); - - } - - private void setMemcachedLoggingLevel(InetSocketAddress address, int level, - boolean noreply) - throws MemcachedException, InterruptedException, TimeoutException { - if (address == null) { - throw new IllegalArgumentException("Null adderss"); - } - CountDownLatch latch = new CountDownLatch(1); - - Queue sessionQueue = this.connector - .getSessionByAddress(address); - if (sessionQueue == null || sessionQueue.peek() == null) { - throw new MemcachedException("could not find session for " - + SystemUtils.getRawAddress(address) + ":" - + address.getPort() + ",maybe it have not been connected"); - } - - Command command = this.commandFactory.createVerbosityCommand(latch, - level, noreply); - final Session session = sessionQueue.peek(); - session.write(command); - if (!noreply) { - this.latchWait(command, this.opTimeout, session); - } - } - - public void setLoggingLevelVerbosityWithNoReply(InetSocketAddress address, - int level) throws InterruptedException, MemcachedException { - try { - this.setMemcachedLoggingLevel(address, level, true); - } catch (TimeoutException e) { - throw new MemcachedException(e); - } - - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#flushAll(java.net. - * InetSocketAddress ) - */ - public final void flushAll(InetSocketAddress address) - throws MemcachedException, InterruptedException, TimeoutException { - this.flushAll(address, this.opTimeout); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#flushAll(java.net. - * InetSocketAddress , long) - */ - public final void flushAll(InetSocketAddress address, long timeout) - throws MemcachedException, InterruptedException, TimeoutException { - this.flushSpecialMemcachedServer(address, timeout, false, 0); - } - - public final void flushAll(InetSocketAddress address, long timeout, - int exptime) - throws MemcachedException, InterruptedException, TimeoutException { - this.flushSpecialMemcachedServer(address, timeout, false, exptime); - } - - private void flushSpecialMemcachedServer(InetSocketAddress address, - long timeout, boolean noreply, int exptime) - throws MemcachedException, InterruptedException, TimeoutException { - if (address == null) { - throw new IllegalArgumentException("Null adderss"); - } - CountDownLatch latch = new CountDownLatch(1); - - Queue sessionQueue = this.connector - .getSessionByAddress(address); - if (sessionQueue == null || sessionQueue.peek() == null) { - throw new MemcachedException("could not find session for " - + SystemUtils.getRawAddress(address) + ":" - + address.getPort() + ",maybe it have not been connected"); - } - Command command = this.commandFactory.createFlushAllCommand(latch, - exptime, noreply); - final Session session = sessionQueue.peek(); - session.write(command); - if (!noreply) { - this.latchWait(command, timeout, session); - } - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#flushAll(java.lang.String) - */ - public final void flushAll(String host) - throws TimeoutException, InterruptedException, MemcachedException { - this.flushAll(AddrUtil.getOneAddress(host), this.opTimeout); - } - - /* - * (non-Javadoc) - * - * @see - * net.rubyeye.xmemcached.MemcachedClient#stats(java.net.InetSocketAddress) - */ - public final Map stats(InetSocketAddress address) - throws MemcachedException, InterruptedException, TimeoutException { - return this.stats(address, this.opTimeout); - } - - /* - * (non-Javadoc) - * - * @see - * net.rubyeye.xmemcached.MemcachedClient#stats(java.net.InetSocketAddress, - * long) - */ - @SuppressWarnings("unchecked") - public final Map stats(InetSocketAddress address, - long timeout) - throws MemcachedException, InterruptedException, TimeoutException { - if (address == null) { - throw new IllegalArgumentException("Null inetSocketAddress"); - } - CountDownLatch latch = new CountDownLatch(1); - - Queue sessionQueue = this.connector - .getSessionByAddress(address); - if (sessionQueue == null || sessionQueue.peek() == null) { - throw new MemcachedException("could not find session for " - + SystemUtils.getRawAddress(address) + ":" - + address.getPort() + ",maybe it have not been connected"); - } - Command command = this.commandFactory.createStatsCommand(address, latch, - null); - final Session session = sessionQueue.peek(); - session.write(command); - this.latchWait(command, timeout, session); - return (Map) command.getResult(); - } - - public final Map> getStats() - throws MemcachedException, InterruptedException, TimeoutException { - return this.getStats(this.opTimeout); - } - - public final Map> getStatsByItem( - String itemName) - throws MemcachedException, InterruptedException, TimeoutException { - return this.getStatsByItem(itemName, this.opTimeout); - } - - @SuppressWarnings("unchecked") - public final Map> getStatsByItem( - String itemName, long timeout) - throws MemcachedException, InterruptedException, TimeoutException { - final Set sessionSet = this.connector.getSessionSet(); - final Map> collectResult = new HashMap>(); - if (sessionSet.size() == 0) { - return collectResult; - } - final CountDownLatch latch = new CountDownLatch(sessionSet.size()); - List commands = new ArrayList(sessionSet.size()); - for (Session session : sessionSet) { - Command command = this.commandFactory.createStatsCommand( - session.getRemoteSocketAddress(), latch, itemName); - - session.write(command); - commands.add(command); - - } - if (!latch.await(timeout, TimeUnit.MILLISECONDS)) { - for (Command command : commands) { - command.cancel(); - } - throw new TimeoutException("Timed out waiting for operation"); - } - for (Command command : commands) { - this.checkException(command); - collectResult.put(((ServerAddressAware) command).getServer(), - (Map) command.getResult()); - } - return collectResult; - } - - public final Map getVersions() - throws TimeoutException, InterruptedException, MemcachedException { - return this.getVersions(this.opTimeout); - } - - public final Map getVersions(long timeout) - throws TimeoutException, InterruptedException, MemcachedException { - final Set sessionSet = this.connector.getSessionSet(); - Map collectResult = new HashMap(); - if (sessionSet.size() == 0) { - return collectResult; - } - final CountDownLatch latch = new CountDownLatch(sessionSet.size()); - List commands = new ArrayList(sessionSet.size()); - for (Session session : sessionSet) { - Command command = this.commandFactory.createVersionCommand(latch, - session.getRemoteSocketAddress()); - session.write(command); - commands.add(command); - - } - - if (!latch.await(timeout, TimeUnit.MILLISECONDS)) { - for (Command command : commands) { - command.cancel(); - } - throw new TimeoutException("Timed out waiting for operation"); - } - for (Command command : commands) { - this.checkException(command); - collectResult.put(((ServerAddressAware) command).getServer(), - (String) command.getResult()); - } - return collectResult; - } - - public Map> getStats(long timeout) - throws MemcachedException, InterruptedException, TimeoutException { - return this.getStatsByItem(null, timeout); - } - - /** - * For subclass override. - */ - protected void shutdown0() { - - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#shutdown() - */ - public final void shutdown() throws IOException { - if (this.shutdown) { - return; - } - this.shutdown0(); - this.shutdown = true; - this.connector.shuttingDown(); - this.connector.quitAllSessions(); - this.connector.stop(); - this.memcachedHandler.stop(); - XMemcachedMbeanServer.getInstance().shutdown(); - if (AddrUtil.isEnableShutDownHook() && !this.isHutdownHookCalled) { - try { - Runtime.getRuntime() - .removeShutdownHook(this.shutdownHookThread); - } catch (Exception e) { - // ignore; - } - } - } - - private long sendIncrOrDecrCommand(final String key, final long delta, - long initValue, final CommandType cmdType, boolean noreply, - long operationTimeout, int exp) - throws InterruptedException, TimeoutException, MemcachedException { - final byte[] keyBytes = ByteUtils.getBytes(key); - ByteUtils.checkKey(keyBytes); - final Command command = this.commandFactory.createIncrDecrCommand(key, - keyBytes, delta, initValue, exp, cmdType, noreply); - final Session session = this.sendCommand(command); - if (!command.isNoreply()) { - this.latchWait(command, operationTimeout, session); - command.getIoBuffer().free(); - this.checkException(command); - if (command.getResult() == null) { - throw new MemcachedException( - "Operation fail,may be caused by networking or timeout"); - } - final Object result = command.getResult(); - if (result instanceof String) { - if (((String) result).equals("NOT_FOUND")) { - if (this.add0(key, exp, String.valueOf(initValue), - this.transcoder, this.opTimeout)) { - return initValue; - } else { - return this.sendIncrOrDecrCommand(key, delta, initValue, - cmdType, noreply, operationTimeout, exp); - } - } else { - throw new MemcachedException( - "Unknown result type for incr/decr:" - + result.getClass() + ",result=" + result); - } - } else { - return (Long) command.getResult(); - } - } else { - return -1; - } - } - - public void setConnectionPoolSize(int poolSize) { - if (!this.shutdown && this.getAvaliableServers().size() > 0) { - throw new IllegalStateException( - "Xmemcached client has been started"); - } - if (poolSize <= 0) { - throw new IllegalArgumentException("poolSize<=0"); - } - this.connectionPoolSize = poolSize; - this.connector.setConnectionPoolSize(poolSize); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#delete(java.lang.String) - */ - public final boolean delete(final String key) - throws TimeoutException, InterruptedException, MemcachedException { - return this.delete(key, 0); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#getTranscoder() - */ - @SuppressWarnings("unchecked") - public final Transcoder getTranscoder() { - return this.transcoder; - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClient#setTranscoder(net.rubyeye. - * xmemcached .transcoders.Transcoder) - */ - @SuppressWarnings("unchecked") - public final void setTranscoder(final Transcoder transcoder) { - this.transcoder = transcoder; - } - - private final boolean sendStoreCommand(Command command, long timeout) - throws InterruptedException, TimeoutException, MemcachedException { - - final Session session = this.sendCommand(command); - if (!command.isNoreply()) { - this.latchWait(command, timeout, session); - command.getIoBuffer().free(); - this.checkException(command); - if (command.getResult() == null) { - throw new MemcachedException( - "Operation fail,may be caused by networking or timeout"); - } - } else { - return false; - } - return (Boolean) command.getResult(); - } - - private static final String CONTINUOUS_TIMEOUT_COUNTER = "ContinuousTimeouts"; - - protected void latchWait(final Command cmd, final long timeout, - final Session session) - throws InterruptedException, TimeoutException { - if (cmd.getLatch().await(timeout, TimeUnit.MILLISECONDS)) { - AtomicInteger counter = this.getContinuousTimeoutCounter(session); - // reset counter. - if (counter.get() > 0) { - counter.set(0); - } - } else { - cmd.cancel(); - AtomicInteger counter = this.getContinuousTimeoutCounter(session); - if (counter.incrementAndGet() > this.timeoutExceptionThreshold) { - log.warn(session - + " exceeded continuous timeout threshold,we will close it."); - try { - // reset counter. - counter.set(0); - session.close(); - } catch (Exception e) { - // ignore it. - } - } - throw new TimeoutException("Timed out(" + timeout - + " milliseconds) waiting for operation while connected to " - + session); - } - } - - private AtomicInteger getContinuousTimeoutCounter(final Session session) { - AtomicInteger counter = (AtomicInteger) session - .getAttribute(CONTINUOUS_TIMEOUT_COUNTER); - if (counter == null) { - counter = new AtomicInteger(0); - AtomicInteger oldCounter = (AtomicInteger) session - .setAttributeIfAbsent(CONTINUOUS_TIMEOUT_COUNTER, counter); - if (oldCounter != null) { - counter = oldCounter; - } - } - return counter; - } - - /** - * Use getAvailableServers() instead - * - * @deprecated - * @see MemcachedClient#getAvailableServers() - */ - @Deprecated - public final Collection getAvaliableServers() { - return this.getAvailableServers(); - } - - public Collection getAvailableServers() { - Set sessionSet = this.connector.getSessionSet(); - Set result = new HashSet(); - for (Session session : sessionSet) { - result.add(session.getRemoteSocketAddress()); - } - return Collections.unmodifiableSet(result); - } - - public final int getConnectionSizeBySocketAddress( - InetSocketAddress address) { - Queue sessionList = this.connector - .getSessionByAddress(address); - return sessionList == null ? 0 : sessionList.size(); - } - - public void addStateListener(MemcachedClientStateListener listener) { - MemcachedClientStateListenerAdapter adapter = new MemcachedClientStateListenerAdapter( - listener, this); - this.stateListenerAdapters.add(adapter); - this.connector.addStateListener(adapter); - } - - public Collection getStateListeners() { - final List result = new ArrayList( - this.stateListenerAdapters.size()); - for (MemcachedClientStateListenerAdapter adapter : this.stateListenerAdapters) { - result.add(adapter.getMemcachedClientStateListener()); - } - return result; - } - - public void setPrimitiveAsString(boolean primitiveAsString) { - this.transcoder.setPrimitiveAsString(primitiveAsString); - } - - public void removeStateListener(MemcachedClientStateListener listener) { - for (MemcachedClientStateListenerAdapter adapter : this.stateListenerAdapters) { - if (adapter.getMemcachedClientStateListener().equals(listener)) { - this.stateListenerAdapters.remove(adapter); - this.connector.removeStateListener(adapter); - } - } - } - - public Protocol getProtocol() { - return this.commandFactory.getProtocol(); - } - - public boolean isSanitizeKeys() { - return this.sanitizeKeys; - } - - public void setSanitizeKeys(boolean sanitizeKeys) { - this.sanitizeKeys = sanitizeKeys; - } - - private String decodeKey(String key) - throws MemcachedException, InterruptedException, TimeoutException { - try { - key = this.sanitizeKeys ? URLDecoder.decode(key, "UTF-8") : key; - } catch (UnsupportedEncodingException e) { - throw new MemcachedException( - "Unsupport encoding utf-8 when decodeKey", e); - } - String ns = NAMESPACE_LOCAL.get(); - if (ns != null && ns.trim().length() > 0) { - String nsValue = this.getNamespace(ns); - try { - if (nsValue != null && key.startsWith(nsValue)) { - // The extra length of ':' - key = key.substring(nsValue.length() + 1); - } else { - return null; - } - } catch (Exception e) { - throw new MemcachedException( - "Exception occured when decode key.", e); - } - } - return key; - } - - private String preProcessKey(String key) - throws MemcachedException, InterruptedException { - key = this.keyProvider.process(key); - try { - key = this.sanitizeKeys ? URLEncoder.encode(key, "UTF-8") : key; - } catch (UnsupportedEncodingException e) { - throw new MemcachedException( - "Unsupport encoding utf-8 when sanitize key", e); - } - String ns = NAMESPACE_LOCAL.get(); - if (ns != null && ns.trim().length() > 0) { - try { - key = this.getNamespace(ns) + ":" + key; - } catch (TimeoutException e) { - throw new MemcachedException( - "Timeout occured when gettting namespace value.", e); - } - } - return key; - } - - public void invalidateNamespace(String ns, long opTimeout) - throws MemcachedException, InterruptedException, TimeoutException { - String key = this.getNSKey(ns); - this.incr(key, 1, System.currentTimeMillis(), opTimeout); - } - - public void invalidateNamespace(String ns) - throws MemcachedException, InterruptedException, TimeoutException { - this.invalidateNamespace(ns, this.opTimeout); - } - - /** - * Returns the real namespace of ns. - * - * @param ns - * @return - * @throws TimeoutException - * @throws InterruptedException - * @throws MemcachedException - */ - public String getNamespace(String ns) - throws TimeoutException, InterruptedException, MemcachedException { - String key = this.keyProvider.process(this.getNSKey(ns)); - byte[] keyBytes = ByteUtils.getBytes(key); - ByteUtils.checkKey(keyBytes); - Object item = this.fetch0(key, keyBytes, CommandType.GET_ONE, - this.opTimeout, this.transcoder); - while (item == null) { - item = String.valueOf(System.nanoTime()); - boolean added = this.add0(key, 0, item, this.transcoder, - this.opTimeout); - if (!added) { - item = this.fetch0(key, keyBytes, CommandType.GET_ONE, - this.opTimeout, this.transcoder); - } - } - String namespace = item.toString(); - if (!ByteUtils.isNumber(namespace)) { - throw new IllegalStateException( - "Namespace key already has value.The key is:" + key - + ",and the value is:" + namespace); - } - return namespace; - } - - private String getNSKey(String ns) { - String key = "namespace:" + ns; - return key; - } - - public Counter getCounter(String key, long initialValue) { - return new Counter(this, key, initialValue); - } - - public Counter getCounter(String key) { - return new Counter(this, key, 0); - } - - /** - * @deprecated memcached 1.6.x will remove cachedump stats command,so this - * method will be removed in the future - */ - @Deprecated - @SuppressWarnings("unchecked") - public KeyIterator getKeyIterator(InetSocketAddress address) - throws MemcachedException, TimeoutException, InterruptedException { - if (address == null) { - throw new IllegalArgumentException("null address"); - } - Queue sessions = this.connector.getSessionByAddress(address); - if (sessions == null || sessions.size() == 0) { - throw new MemcachedException( - "The special memcached server has not been connected," - + address); - } - Session session = sessions.peek(); - CountDownLatch latch = new CountDownLatch(1); - Command command = this.commandFactory.createStatsCommand( - session.getRemoteSocketAddress(), latch, "items"); - session.write(command); - if (!latch.await(5000, TimeUnit.MILLISECONDS)) { - throw new TimeoutException("Operation timeout"); - } - if (command.getException() != null) { - if (command.getException() instanceof MemcachedException) { - throw (MemcachedException) command.getException(); - } else { - throw new MemcachedException("stats items failed", - command.getException()); - } - } - Map result = (Map) command.getResult(); - LinkedList itemNumberList = new LinkedList(); - for (Map.Entry entry : result.entrySet()) { - final String key = entry.getKey(); - final String[] keys = key.split(":"); - if (keys.length == 3 && keys[2].equals("number") - && keys[0].equals("items")) { - // has items,then add it to itemNumberList - if (Integer.parseInt(entry.getValue()) > 0) { - itemNumberList.add(Integer.parseInt(keys[1])); - } - } - } - return new KeyIteratorImpl(itemNumberList, this, address); - } - - public void setEnableHealSession(boolean enableHealSession) { - if (this.connector != null) { - this.connector.setEnableHealSession(enableHealSession); - } else { - throw new IllegalStateException("The client has not been started."); - } - } - - public void setFailureMode(boolean failureMode) { - this.failureMode = failureMode; - if (this.sessionLocator != null) { - this.sessionLocator.setFailureMode(failureMode); - } - if (this.connector != null) { - this.connector.setFailureMode(failureMode); - } - } - - public boolean isFailureMode() { - return this.failureMode; - } - - public Queue getReconnectRequestQueue() { - return this.connector != null - ? this.connector.getReconnectRequestQueue() - : null; - } +public class XMemcachedClient implements XMemcachedClientMBean, MemcachedClient { + + private static final Logger log = LoggerFactory.getLogger(XMemcachedClient.class); + protected MemcachedSessionLocator sessionLocator; + private volatile boolean shutdown; + protected MemcachedConnector connector; + @SuppressWarnings("unchecked") + private Transcoder transcoder; + private boolean sanitizeKeys; + private MemcachedHandler memcachedHandler; + protected CommandFactory commandFactory; + protected long opTimeout = DEFAULT_OP_TIMEOUT; + private long connectTimeout = DEFAULT_CONNECT_TIMEOUT; + protected int connectionPoolSize = DEFAULT_CONNECTION_POOL_SIZE; + protected int maxQueuedNoReplyOperations = DEFAULT_MAX_QUEUED_NOPS; + + protected final AtomicInteger serverOrderCount = new AtomicInteger(); + + private Map authInfoMap = new HashMap(); + + private String name; // cache name + + private boolean failureMode; + + private int timeoutExceptionThreshold = DEFAULT_MAX_TIMEOUTEXCEPTION_THRESHOLD; + + private final CopyOnWriteArrayList stateListenerAdapters = + new CopyOnWriteArrayList(); + private Thread shutdownHookThread; + + private volatile boolean isHutdownHookCalled = false; + // key provider for pre-processing keys before sending them to memcached + // added by dennis,2012-07-14 + private KeyProvider keyProvider = DefaultKeyProvider.INSTANCE; + /** + * namespace thread local. + */ + public static final ThreadLocal NAMESPACE_LOCAL = new ThreadLocal(); + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#setMergeFactor(int) + */ + public final void setMergeFactor(final int mergeFactor) { + if (mergeFactor < 0) { + throw new IllegalArgumentException("mergeFactor<0"); + } + this.connector.setMergeFactor(mergeFactor); + } + + public int getTimeoutExceptionThreshold() { + return this.timeoutExceptionThreshold; + } + + public void setTimeoutExceptionThreshold(int timeoutExceptionThreshold) { + if (timeoutExceptionThreshold <= 0) { + throw new IllegalArgumentException( + "Illegal timeoutExceptionThreshold value " + timeoutExceptionThreshold); + } + if (timeoutExceptionThreshold < 100) { + log.warn( + "Too small timeoutExceptionThreshold value may cause connections disconnect/reconnect frequently."); + } + this.timeoutExceptionThreshold = timeoutExceptionThreshold; + } + + public T withNamespace(String ns, MemcachedClientCallable callable) + throws MemcachedException, InterruptedException, TimeoutException { + this.beginWithNamespace(ns); + try { + return callable.call(this); + } finally { + this.endWithNamespace(); + } + } + + public void endWithNamespace() { + NAMESPACE_LOCAL.remove(); + } + + public void beginWithNamespace(String ns) { + if (ns == null || ns.trim().length() == 0) { + throw new IllegalArgumentException("Blank namespace"); + } + if (NAMESPACE_LOCAL.get() != null) { + throw new IllegalStateException("Previous namespace wasn't ended."); + } + NAMESPACE_LOCAL.set(ns); + } + + public KeyProvider getKeyProvider() { + return this.keyProvider; + } + + public void setKeyProvider(KeyProvider keyProvider) { + if (keyProvider == null) { + throw new IllegalArgumentException("Null key provider"); + } + this.keyProvider = keyProvider; + } + + public final MemcachedSessionLocator getSessionLocator() { + return this.sessionLocator; + } + + public final CommandFactory getCommandFactory() { + return this.commandFactory; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#getConnectTimeout() + */ + public long getConnectTimeout() { + return this.connectTimeout; + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#setConnectTimeout(long) + */ + public void setConnectTimeout(long connectTimeout) { + if (connectTimeout < 0) { + throw new IllegalArgumentException("connectTimeout<0"); + } + this.connectTimeout = connectTimeout; + } + + public void setEnableHeartBeat(boolean enableHeartBeat) { + this.memcachedHandler.setEnableHeartBeat(enableHeartBeat); + } + + /** + * get operation timeout setting + * + * @return + */ + public final long getOpTimeout() { + return this.opTimeout; + } + + /** + * set operation timeout,default is one second. + * + * @param opTimeout + */ + public final void setOpTimeout(long opTimeout) { + if (opTimeout < 0) { + throw new IllegalArgumentException("opTimeout<0"); + } + this.opTimeout = opTimeout; + } + + public void setHealSessionInterval(long healConnectionInterval) { + if (healConnectionInterval <= 0) { + throw new IllegalArgumentException("Invalid heal session interval:" + healConnectionInterval); + } + if (null != this.connector) { + this.connector.setHealSessionInterval(healConnectionInterval); + } else { + throw new IllegalStateException("The client hasn't been started"); + } + } + + public long getHealSessionInterval() { + if (null != this.connector) { + return this.connector.getHealSessionInterval(); + } + return -1L; + } + + public Map getAuthInfoMap() { + return this.authInfoMap; + } + + public void setAuthInfoMap(Map map) { + this.authInfoMap = map; + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#getConnector() + */ + public final Connector getConnector() { + return this.connector; + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#setOptimizeMergeBuffer(boolean) + */ + public final void setOptimizeMergeBuffer(final boolean optimizeMergeBuffer) { + this.connector.setOptimizeMergeBuffer(optimizeMergeBuffer); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#isShutdown() + */ + public final boolean isShutdown() { + return this.shutdown; + } + + @SuppressWarnings("unchecked") + private final GetsResponse gets0(final String key, final byte[] keyBytes, + final Transcoder transcoder) + throws MemcachedException, TimeoutException, InterruptedException { + GetsResponse result = (GetsResponse) this.fetch0(key, keyBytes, CommandType.GETS_ONE, + this.opTimeout, transcoder); + return result; + } + + protected final Session sendCommand(final Command cmd) throws MemcachedException { + if (this.shutdown) { + throw new MemcachedException("Xmemcached is stopped"); + } + return this.connector.send(cmd); + } + + /** + * XMemcached constructor,default weight is 1 + * + * @param server �����P + * @param port ����ㄧ��� + * @throws IOException + */ + public XMemcachedClient(final String server, final int port) throws IOException { + this(server, port, 1); + } + + /** + * XMemcached constructor + * + * @param host server host + * @param port server port + * @param weight server weight + * @throws IOException + */ + public XMemcachedClient(final String host, final int port, int weight) throws IOException { + super(); + if (weight <= 0) { + throw new IllegalArgumentException("weight<=0"); + } + this.checkServerPort(host, port); + this.buildConnector(new ArrayMemcachedSessionLocator(), new SimpleBufferAllocator(), + XMemcachedClientBuilder.getDefaultConfiguration(), + XMemcachedClientBuilder.getDefaultSocketOptions(), new TextCommandFactory(), + new SerializingTranscoder()); + this.start0(); + this.connect(new InetSocketAddressWrapper(this.newSocketAddress(host, port), + this.serverOrderCount.incrementAndGet(), weight, null)); + } + + protected InetSocketAddress newSocketAddress(final String server, final int port) { + return new InetSocketAddress(server, port); + } + + private void checkServerPort(String server, int port) { + if (server == null || server.length() == 0) { + throw new IllegalArgumentException(); + } + if (port <= 0) { + throw new IllegalArgumentException(); + } + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#addServer(java.lang.String, int) + */ + public final void addServer(final String server, final int port) throws IOException { + this.addServer(server, port, 1); + } + + /** + * add a memcached server to MemcachedClient + * + * @param server + * @param port + * @param weight + * @throws IOException + */ + public final void addServer(final String server, final int port, int weight) throws IOException { + if (weight <= 0) { + throw new IllegalArgumentException("weight<=0"); + } + this.checkServerPort(server, port); + this.connect(new InetSocketAddressWrapper(this.newSocketAddress(server, port), + this.serverOrderCount.incrementAndGet(), weight, null)); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#addServer(java.net. InetSocketAddress ) + */ + public final void addServer(final InetSocketAddress inetSocketAddress) throws IOException { + this.addServer(inetSocketAddress, 1); + } + + public final void addServer(final InetSocketAddress inetSocketAddress, int weight) + throws IOException { + if (inetSocketAddress == null) { + throw new IllegalArgumentException("Null InetSocketAddress"); + } + if (weight <= 0) { + throw new IllegalArgumentException("weight<=0"); + } + this.connect(new InetSocketAddressWrapper(inetSocketAddress, + this.serverOrderCount.incrementAndGet(), weight, null)); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#addServer(java.lang.String) + */ + public final void addServer(String hostList) throws IOException { + Map addresses = AddrUtil.getAddressMap(hostList); + if (addresses != null && addresses.size() > 0) { + for (Map.Entry entry : addresses.entrySet()) { + final InetSocketAddress mainNodeAddr = entry.getKey(); + final InetSocketAddress standbyNodeAddr = entry.getValue(); + this.connect(new InetSocketAddressWrapper(mainNodeAddr, + this.serverOrderCount.incrementAndGet(), 1, null)); + if (standbyNodeAddr != null) { + this.connect(new InetSocketAddressWrapper(standbyNodeAddr, + this.serverOrderCount.incrementAndGet(), 1, mainNodeAddr)); + } + } + } + } + + public void addOneServerWithWeight(String server, int weight) throws IOException { + Map addresses = AddrUtil.getAddressMap(server); + if (addresses == null) { + throw new IllegalArgumentException("Null Server"); + } + if (addresses.size() != 1) { + throw new IllegalArgumentException("Please add one server at one time"); + } + if (weight <= 0) { + throw new IllegalArgumentException("weight<=0"); + } + if (addresses != null && addresses.size() > 0) { + for (Map.Entry entry : addresses.entrySet()) { + final InetSocketAddress mainNodeAddr = entry.getKey(); + final InetSocketAddress standbyNodeAddr = entry.getValue(); + this.connect(new InetSocketAddressWrapper(mainNodeAddr, + this.serverOrderCount.incrementAndGet(), 1, null)); + if (standbyNodeAddr != null) { + this.connect(new InetSocketAddressWrapper(standbyNodeAddr, + this.serverOrderCount.incrementAndGet(), 1, mainNodeAddr)); + } + } + } + + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#getServersDescription() + */ + public final List getServersDescription() { + final List result = new ArrayList(); + for (Session session : this.connector.getSessionSet()) { + InetSocketAddress socketAddress = session.getRemoteSocketAddress(); + int weight = ((MemcachedSession) session).getInetSocketAddressWrapper().getWeight(); + result.add(SystemUtils.getRawAddress(socketAddress) + ":" + socketAddress.getPort() + + "(weight=" + weight + ")"); + } + return result; + } + + public final void setServerWeight(String server, int weight) { + InetSocketAddress socketAddress = AddrUtil.getOneAddress(server); + Queue sessionQueue = this.connector.getSessionByAddress(socketAddress); + if (sessionQueue == null) { + throw new IllegalArgumentException("There is no server " + server); + } + for (Session session : sessionQueue) { + if (session != null) { + ((MemcachedTCPSession) session).getInetSocketAddressWrapper().setWeight(weight); + } + } + this.connector.updateSessions(); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#removeServer(java.lang.String) + */ + public final void removeServer(String hostList) { + List addresses = AddrUtil.getAddresses(hostList); + if (addresses != null && addresses.size() > 0) { + for (InetSocketAddress address : addresses) { + removeAddr(address); + } + + } + + } + + protected void removeAddr(InetSocketAddress address) { + // Close main sessions + Queue sessionQueue = this.connector.getSessionByAddress(address); + if (sessionQueue != null) { + for (Session session : sessionQueue) { + if (session != null) { + // Disable auto reconnection + ((MemcachedSession) session).setAllowReconnect(false); + // Close connection + ((MemcachedSession) session).quit(); + } + } + } + // Close standby sessions + List standBySession = this.connector.getStandbySessionListByMainNodeAddr(address); + if (standBySession != null) { + for (Session session : standBySession) { + if (session != null) { + this.connector.removeReconnectRequest(session.getRemoteSocketAddress()); + // Disable auto reconnection + ((MemcachedSession) session).setAllowReconnect(false); + // Close connection + ((MemcachedSession) session).quit(); + } + } + } + this.connector.removeReconnectRequest(address); + } + + protected void connect(final InetSocketAddressWrapper inetSocketAddressWrapper) + throws IOException { + // creat connection pool + InetSocketAddress inetSocketAddress = inetSocketAddressWrapper.getInetSocketAddress(); + if (this.connectionPoolSize > 1) { + log.warn( + "You are using connection pool for xmemcached client,it's not recommended unless you have test it that it can boost performance in your app."); + } + for (int i = 0; i < this.connectionPoolSize; i++) { + Future future = null; + boolean connected = false; + Throwable throwable = null; + try { + future = this.connector.connect(inetSocketAddressWrapper); + + if (!future.get(this.connectTimeout, TimeUnit.MILLISECONDS)) { + log.error("connect to " + SystemUtils.getRawAddress(inetSocketAddress) + ":" + + inetSocketAddress.getPort() + " fail"); + } else { + connected = true; + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } catch (ExecutionException e) { + throwable = e; + log.error("connect to " + SystemUtils.getRawAddress(inetSocketAddress) + ":" + + inetSocketAddress.getPort() + " error", e); + } catch (TimeoutException e) { + throwable = e; + log.error("connect to " + SystemUtils.getRawAddress(inetSocketAddress) + ":" + + inetSocketAddress.getPort() + " timeout", e); + } catch (Exception e) { + throwable = e; + log.error("connect to " + SystemUtils.getRawAddress(inetSocketAddress) + ":" + + inetSocketAddress.getPort() + " error", e); + } + // If it is not connected,it will be added to waiting queue for + // reconnecting. + if (!connected) { + if (future != null) { + future.cancel(true); + } + // If we use failure mode, add a mock session at first + if (this.failureMode) { + this.connector.addSession(new ClosedMemcachedTCPSession(inetSocketAddressWrapper)); + } + this.connector.addToWatingQueue( + new ReconnectRequest(inetSocketAddressWrapper, 0, this.getHealSessionInterval())); + log.error("Connect to " + SystemUtils.getRawAddress(inetSocketAddress) + ":" + + inetSocketAddress.getPort() + " fail", throwable); + // throw new IOException(throwable); + } + } + } + + @SuppressWarnings("unchecked") + private final Object fetch0(final String key, final byte[] keyBytes, + final CommandType cmdType, final long timeout, Transcoder transcoder) + throws InterruptedException, TimeoutException, MemcachedException { + final Command command = + this.commandFactory.createGetCommand(key, keyBytes, cmdType, this.transcoder); + this.latchWait(command, timeout, this.sendCommand(command)); + command.getIoBuffer().free(); // free buffer + this.checkException(command); + CachedData data = (CachedData) command.getResult(); + if (data == null) { + return null; + } + if (transcoder == null) { + transcoder = this.transcoder; + } + if (cmdType == CommandType.GETS_ONE) { + return new GetsResponse(data.getCas(), transcoder.decode(data)); + } else { + return transcoder.decode(data); + } + } + + private final void start0() throws IOException { + this.registerMBean(); + this.startConnector(); + MemcachedClientNameHolder.clear(); + } + + private final void startConnector() throws IOException { + if (this.shutdown) { + this.shutdown = false; + this.connector.start(); + this.memcachedHandler.start(); + if (AddrUtil.isEnableShutDownHook()) { + this.shutdownHookThread = new Thread() { + @Override + public void run() { + try { + XMemcachedClient.this.isHutdownHookCalled = true; + XMemcachedClient.this.shutdown(); + } catch (IOException e) { + log.error("Shutdown XMemcachedClient error", e); + } + } + }; + Runtime.getRuntime().addShutdownHook(this.shutdownHookThread); + } + } + } + + /** + * Set max queued noreply operations number + * + * @param maxQueuedNoReplyOperations + */ + void setMaxQueuedNoReplyOperations(int maxQueuedNoReplyOperations) { + if (maxQueuedNoReplyOperations <= 1) { + throw new IllegalArgumentException("maxQueuedNoReplyOperations<=1"); + } + this.maxQueuedNoReplyOperations = maxQueuedNoReplyOperations; + } + + @SuppressWarnings("unchecked") + private void buildConnector(MemcachedSessionLocator locator, BufferAllocator bufferAllocator, + Configuration configuration, Map socketOptions, + CommandFactory commandFactory, Transcoder transcoder) { + if (locator == null) { + locator = new ArrayMemcachedSessionLocator(); + + } + if (bufferAllocator == null) { + bufferAllocator = new SimpleBufferAllocator(); + } + if (configuration == null) { + configuration = XMemcachedClientBuilder.getDefaultConfiguration(); + } + if (transcoder == null) { + transcoder = new SerializingTranscoder(); + } + if (commandFactory == null) { + commandFactory = new TextCommandFactory(); + } + if (this.name == null) { + this.name = "MemcachedClient-" + Constants.MEMCACHED_CLIENT_COUNTER.getAndIncrement(); + MemcachedClientNameHolder.setName(this.name); + } + this.commandFactory = commandFactory; + ByteUtils.setProtocol(this.commandFactory.getProtocol()); + log.info("XMemcachedClient is using " + this.commandFactory.getProtocol().name() + " protocol"); + this.commandFactory.setBufferAllocator(bufferAllocator); + this.shutdown = true; + this.transcoder = transcoder; + this.sessionLocator = locator; + this.connector = this.newConnector(bufferAllocator, configuration, this.sessionLocator, + this.commandFactory, this.connectionPoolSize, this.maxQueuedNoReplyOperations); + this.memcachedHandler = new MemcachedHandler(this); + this.connector.setHandler(this.memcachedHandler); + this.connector.setCodecFactory(new MemcachedCodecFactory()); + this.connector.setSessionTimeout(-1); + this.connector.setSocketOptions(socketOptions); + if (this.isFailureMode()) { + log.info("XMemcachedClient in failure mode."); + } + this.connector.setFailureMode(this.failureMode); + this.sessionLocator.setFailureMode(this.failureMode); + } + + protected MemcachedConnector newConnector(BufferAllocator bufferAllocator, + Configuration configuration, MemcachedSessionLocator memcachedSessionLocator, + CommandFactory commandFactory, int poolSize, int maxQueuedNoReplyOperations) { + // make sure dispatch message thread count is zero + configuration.setDispatchMessageThreadCount(0); + return new MemcachedConnector(configuration, memcachedSessionLocator, bufferAllocator, + commandFactory, poolSize, maxQueuedNoReplyOperations); + } + + private final void registerMBean() { + if (this.shutdown) { + XMemcachedMbeanServer.getInstance().registMBean(this, this.getClass().getPackage().getName() + + ":type=" + this.getClass().getSimpleName() + "-" + MemcachedClientNameHolder.getName()); + } + } + + public void setOptimizeGet(boolean optimizeGet) { + this.connector.setOptimizeGet(optimizeGet); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#setBufferAllocator(net.rubyeye + * .xmemcached.buffer.BufferAllocator) + */ + public final void setBufferAllocator(final BufferAllocator bufferAllocator) { + this.connector.setBufferAllocator(bufferAllocator); + } + + /** + * XMemcached Constructor. + * + * @param inetSocketAddress + * @param weight + * @throws IOException + */ + public XMemcachedClient(final InetSocketAddress inetSocketAddress, int weight, + CommandFactory cmdFactory) throws IOException { + super(); + if (inetSocketAddress == null) { + throw new IllegalArgumentException("Null InetSocketAddress"); + + } + if (cmdFactory == null) { + throw new IllegalArgumentException("Null command factory."); + } + if (weight <= 0) { + throw new IllegalArgumentException("weight<=0"); + } + this.buildConnector(new ArrayMemcachedSessionLocator(), new SimpleBufferAllocator(), + XMemcachedClientBuilder.getDefaultConfiguration(), + XMemcachedClientBuilder.getDefaultSocketOptions(), cmdFactory, new SerializingTranscoder()); + this.start0(); + this.connect(new InetSocketAddressWrapper(inetSocketAddress, + this.serverOrderCount.incrementAndGet(), weight, null)); + } + + public XMemcachedClient(final InetSocketAddress inetSocketAddress, int weight) + throws IOException { + this(inetSocketAddress, weight, new TextCommandFactory()); + } + + public XMemcachedClient(final InetSocketAddress inetSocketAddress) throws IOException { + this(inetSocketAddress, 1); + } + + public XMemcachedClient() throws IOException { + super(); + this.buildConnector(new ArrayMemcachedSessionLocator(), new SimpleBufferAllocator(), + XMemcachedClientBuilder.getDefaultConfiguration(), + XMemcachedClientBuilder.getDefaultSocketOptions(), new TextCommandFactory(), + new SerializingTranscoder()); + this.start0(); + } + + /** + * XMemcachedClient constructor.Every server's weight is one by default. You should not new client + * instance by this method, use MemcachedClientBuilder instead. + * + * @param locator + * @param allocator + * @param conf + * @param commandFactory + * @param transcoder + * @param addressList + * @param stateListeners + * @throws IOException + */ + @SuppressWarnings("unchecked") + public XMemcachedClient(MemcachedSessionLocator locator, BufferAllocator allocator, + Configuration conf, Map socketOptions, CommandFactory commandFactory, + Transcoder transcoder, Map addressMap, + List stateListeners, Map map, + int poolSize, long connectTimeout, String name, boolean failureMode) throws IOException { + super(); + this.setConnectTimeout(connectTimeout); + this.setFailureMode(failureMode); + this.setName(name); + this.optimiezeSetReadThreadCount(conf, addressMap == null ? 0 : addressMap.size()); + this.buildConnector(locator, allocator, conf, socketOptions, commandFactory, transcoder); + if (stateListeners != null) { + for (MemcachedClientStateListener stateListener : stateListeners) { + this.addStateListener(stateListener); + } + } + this.setAuthInfoMap(map); + this.setConnectionPoolSize(poolSize); + this.start0(); + if (addressMap != null) { + for (Map.Entry entry : addressMap.entrySet()) { + final InetSocketAddress mainNodeAddr = entry.getKey(); + final InetSocketAddress standbyNodeAddr = entry.getValue(); + this.connect(new InetSocketAddressWrapper(mainNodeAddr, + this.serverOrderCount.incrementAndGet(), 1, null)); + if (standbyNodeAddr != null) { + this.connect(new InetSocketAddressWrapper(standbyNodeAddr, + this.serverOrderCount.incrementAndGet(), 1, mainNodeAddr)); + } + } + } + } + + /** + * XMemcachedClient constructor. + * + * @param locator + * @param allocator + * @param conf + * @param commandFactory + * @param transcoder + * @param addressList + * @param weights + * @param stateListeners weight array for address list + * @throws IOException + */ + @SuppressWarnings("unchecked") + XMemcachedClient(MemcachedSessionLocator locator, BufferAllocator allocator, Configuration conf, + Map socketOptions, CommandFactory commandFactory, Transcoder transcoder, + Map addressMap, int[] weights, + List stateListeners, Map infoMap, + int poolSize, long connectTimeout, final String name, boolean failureMode) + throws IOException { + super(); + this.setConnectTimeout(connectTimeout); + this.setFailureMode(failureMode); + this.setName(name); + if (weights == null && addressMap != null) { + throw new IllegalArgumentException("Null weights"); + } + if (weights != null && addressMap == null) { + throw new IllegalArgumentException("Null addressList"); + } + + if (weights != null) { + for (int weight : weights) { + if (weight <= 0) { + throw new IllegalArgumentException("Some weights<=0"); + } + } + } + if (weights != null && addressMap != null && weights.length < addressMap.size()) { + throw new IllegalArgumentException("weights.length is less than addressList.size()"); + } + this.optimiezeSetReadThreadCount(conf, addressMap == null ? 0 : addressMap.size()); + this.buildConnector(locator, allocator, conf, socketOptions, commandFactory, transcoder); + if (stateListeners != null) { + for (MemcachedClientStateListener stateListener : stateListeners) { + this.addStateListener(stateListener); + } + } + this.setAuthInfoMap(infoMap); + this.setConnectionPoolSize(poolSize); + this.start0(); + if (addressMap != null && weights != null) { + int i = 0; + for (Map.Entry entry : addressMap.entrySet()) { + final InetSocketAddress mainNodeAddr = entry.getKey(); + final InetSocketAddress standbyNodeAddr = entry.getValue(); + this.connect(new InetSocketAddressWrapper(mainNodeAddr, + this.serverOrderCount.incrementAndGet(), weights[i], null)); + if (standbyNodeAddr != null) { + this.connect(new InetSocketAddressWrapper(standbyNodeAddr, + this.serverOrderCount.incrementAndGet(), weights[i], mainNodeAddr)); + } + i++; + } + } + } + + private final void optimiezeSetReadThreadCount(Configuration conf, int addressCount) { + if (conf != null && addressCount > 1) { + if (!this.isWindowsPlatform() && conf.getReadThreadCount() == DEFAULT_READ_THREAD_COUNT) { + int threadCount = SystemUtils.getSystemThreadCount(); + conf.setReadThreadCount(addressCount > threadCount ? threadCount : addressCount); + } + } + } + + private final boolean isWindowsPlatform() { + String osName = System.getProperty("os.name"); + if (osName != null && osName.toLowerCase().indexOf("windows") >= 0) { + return true; + } else { + return false; + } + } + + /** + * XMemcached Constructor.Every server's weight is one by default. + * + * @param addressList + * @throws IOException + */ + public XMemcachedClient(List addressList) throws IOException { + this(addressList, new TextCommandFactory()); + } + + /** + * XMemcached Constructor.Every server's weight is one by default. + * + * @param cmdFactory command factory + * @param addressList memcached server socket address list. + * @throws IOException + */ + public XMemcachedClient(List addressList, CommandFactory cmdFactory) + throws IOException { + super(); + if (cmdFactory == null) { + throw new IllegalArgumentException("Null command factory."); + } + if (addressList == null || addressList.isEmpty()) { + throw new IllegalArgumentException("Empty address list"); + } + BufferAllocator simpleBufferAllocator = new SimpleBufferAllocator(); + this.buildConnector(new ArrayMemcachedSessionLocator(), simpleBufferAllocator, + XMemcachedClientBuilder.getDefaultConfiguration(), + XMemcachedClientBuilder.getDefaultSocketOptions(), cmdFactory, new SerializingTranscoder()); + this.start0(); + for (InetSocketAddress inetSocketAddress : addressList) { + this.connect(new InetSocketAddressWrapper(inetSocketAddress, + this.serverOrderCount.incrementAndGet(), 1, null)); + + } + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#get(java.lang.String, long, + * net.rubyeye.xmemcached.transcoders.Transcoder) + */ + @SuppressWarnings("unchecked") + public final T get(final String key, final long timeout, final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException { + return (T) this.get0(key, timeout, CommandType.GET_ONE, transcoder); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#get(java.lang.String, long) + */ + @SuppressWarnings("unchecked") + public final T get(final String key, final long timeout) + throws TimeoutException, InterruptedException, MemcachedException { + return (T) this.get(key, timeout, this.transcoder); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#get(java.lang.String, + * net.rubyeye.xmemcached.transcoders.Transcoder) + */ + public final T get(final String key, final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException { + return this.get(key, this.opTimeout, transcoder); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#get(java.lang.String) + */ + @SuppressWarnings("unchecked") + public final T get(final String key) + throws TimeoutException, InterruptedException, MemcachedException { + return (T) this.get(key, this.opTimeout); + } + + private Object get0(String key, final long timeout, final CommandType cmdType, + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException { + key = this.preProcessKey(key); + byte[] keyBytes = ByteUtils.getBytes(key); + ByteUtils.checkKey(keyBytes); + return this.fetch0(key, keyBytes, cmdType, timeout, transcoder); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#gets(java.lang.String, long, + * net.rubyeye.xmemcached.transcoders.Transcoder) + */ + @SuppressWarnings("unchecked") + public final GetsResponse gets(final String key, final long timeout, + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException { + return (GetsResponse) this.get0(key, timeout, CommandType.GETS_ONE, transcoder); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#gets(java.lang.String) + */ + public final GetsResponse gets(final String key) + throws TimeoutException, InterruptedException, MemcachedException { + return this.gets(key, this.opTimeout); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#gets(java.lang.String, long) + */ + @SuppressWarnings("unchecked") + public final GetsResponse gets(final String key, final long timeout) + throws TimeoutException, InterruptedException, MemcachedException { + return this.gets(key, timeout, this.transcoder); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#gets(java.lang.String, + * net.rubyeye.xmemcached.transcoders.Transcoder) + */ + @SuppressWarnings("unchecked") + public final GetsResponse gets(final String key, final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException { + return this.gets(key, this.opTimeout, transcoder); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#get(java.util.Collection, long, + * net.rubyeye.xmemcached.transcoders.Transcoder) + */ + public final Map get(final Collection keyCollections, final long timeout, + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException { + return this.getMulti0(keyCollections, timeout, CommandType.GET_MANY, transcoder); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#get(java.util.Collection, + * net.rubyeye.xmemcached.transcoders.Transcoder) + */ + public final Map get(final Collection keyCollections, + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException { + return this.getMulti0(keyCollections, this.opTimeout, CommandType.GET_MANY, transcoder); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#get(java.util.Collection) + */ + public final Map get(final Collection keyCollections) + throws TimeoutException, InterruptedException, MemcachedException { + return this.get(keyCollections, this.opTimeout); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#get(java.util.Collection, long) + */ + @SuppressWarnings("unchecked") + public final Map get(final Collection keyCollections, final long timeout) + throws TimeoutException, InterruptedException, MemcachedException { + return this.get(keyCollections, timeout, this.transcoder); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#gets(java.util.Collection, long, + * net.rubyeye.xmemcached.transcoders.Transcoder) + */ + @SuppressWarnings("unchecked") + public final Map> gets(final Collection keyCollections, + final long timeout, final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException { + return (Map>) this.getMulti0(keyCollections, timeout, + CommandType.GETS_MANY, transcoder); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#gets(java.util.Collection) + */ + public final Map> gets(final Collection keyCollections) + throws TimeoutException, InterruptedException, MemcachedException { + return this.gets(keyCollections, this.opTimeout); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#gets(java.util.Collection, long) + */ + @SuppressWarnings("unchecked") + public final Map> gets(final Collection keyCollections, + final long timeout) throws TimeoutException, InterruptedException, MemcachedException { + return this.gets(keyCollections, timeout, this.transcoder); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#gets(java.util.Collection, + * net.rubyeye.xmemcached.transcoders.Transcoder) + */ + public final Map> gets(final Collection keyCollections, + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException { + return this.gets(keyCollections, this.opTimeout, transcoder); + } + + private final Map getMulti0(final Collection keys, final long timeout, + final CommandType cmdType, final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException { + if (keys == null || keys.size() == 0) { + return null; + } + Collection keyCollections = new ArrayList(keys.size()); + for (String key : keys) { + keyCollections.add(this.preProcessKey(key)); + } + final CountDownLatch latch; + final List commands; + if (this.connector.getSessionSet().size() <= 1) { + commands = new ArrayList(1); + latch = new CountDownLatch(1); + commands.add(this.sendGetMultiCommand(keyCollections, latch, cmdType, transcoder)); + + } else { + Collection> catalogKeys = this.catalogKeys(keyCollections); + commands = new ArrayList(catalogKeys.size()); + latch = new CountDownLatch(catalogKeys.size()); + for (List catalogKeyCollection : catalogKeys) { + commands.add(this.sendGetMultiCommand(catalogKeyCollection, latch, cmdType, transcoder)); + } + } + if (!latch.await(timeout, TimeUnit.MILLISECONDS)) { + for (Command getCmd : commands) { + getCmd.cancel(); + } + throw new TimeoutException("Timed out waiting for operation"); + } + return this.reduceResult(cmdType, transcoder, commands); + } + + @SuppressWarnings("unchecked") + private Map reduceResult(final CommandType cmdType, final Transcoder transcoder, + final List commands) + throws MemcachedException, InterruptedException, TimeoutException { + final Map result = new HashMap(commands.size()); + for (Command getCmd : commands) { + getCmd.getIoBuffer().free(); + this.checkException(getCmd); + Map map = (Map) getCmd.getResult(); + if (cmdType == CommandType.GET_MANY) { + Iterator> it = map.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry entry = it.next(); + String decodeKey = this.decodeKey(entry.getKey()); + if (decodeKey != null) { + result.put(decodeKey, transcoder.decode(entry.getValue())); + } + } + + } else { + Iterator> it = map.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry entry = it.next(); + GetsResponse getsResponse = + new GetsResponse(entry.getValue().getCas(), transcoder.decode(entry.getValue())); + String decodeKey = this.decodeKey(entry.getKey()); + if (decodeKey != null) { + result.put(decodeKey, (T) getsResponse); + } + } + + } + + } + return result; + } + + /** + * Hash key to servers + * + * @param keyCollections + * @return + */ + private final Collection> catalogKeys(final Collection keyCollections) { + final Map> catalogMap = new HashMap>(); + + for (String key : keyCollections) { + Session index = this.sessionLocator.getSessionByKey(key); + List tmpKeys = catalogMap.get(index); + if (tmpKeys == null) { + tmpKeys = new ArrayList(10); + catalogMap.put(index, tmpKeys); + } + tmpKeys.add(key); + } + + Collection> catalogKeys = catalogMap.values(); + return catalogKeys; + } + + private final Command sendGetMultiCommand(final Collection keys, + final CountDownLatch latch, final CommandType cmdType, final Transcoder transcoder) + throws InterruptedException, TimeoutException, MemcachedException { + final Command command = + this.commandFactory.createGetMultiCommand(keys, latch, cmdType, transcoder); + this.sendCommand(command); + return command; + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#set(java.lang.String, int, T, + * net.rubyeye.xmemcached.transcoders.Transcoder, long) + */ + public final boolean set(String key, final int exp, final T value, + final Transcoder transcoder, final long timeout) + throws TimeoutException, InterruptedException, MemcachedException { + key = this.preProcessKey(key); + byte[] keyBytes = this.checkStoreArguments(key, exp, value); + return this.sendStoreCommand( + this.commandFactory.createSetCommand(key, keyBytes, exp, value, false, transcoder), + timeout); + } + + @SuppressWarnings("unchecked") + public void setWithNoReply(String key, int exp, Object value) + throws InterruptedException, MemcachedException { + this.setWithNoReply(key, exp, value, this.transcoder); + } + + public void setWithNoReply(String key, int exp, T value, Transcoder transcoder) + throws InterruptedException, MemcachedException { + key = this.preProcessKey(key); + byte[] keyBytes = this.checkStoreArguments(key, exp, value); + try { + this.sendStoreCommand( + this.commandFactory.createSetCommand(key, keyBytes, exp, value, true, transcoder), + this.opTimeout); + } catch (TimeoutException e) { + throw new MemcachedException(e); + } + } + + private final byte[] checkStoreArguments(final String key, final int exp, final T value) { + byte[] keyBytes = ByteUtils.getBytes(key); + ByteUtils.checkKey(keyBytes); + if (value == null) { + throw new IllegalArgumentException("value could not be null"); + } + if (exp < 0) { + throw new IllegalArgumentException("Expire time must be greater than or equal to 0"); + } + return keyBytes; + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#set(java.lang.String, int, java.lang.Object) + */ + public final boolean set(final String key, final int exp, final Object value) + throws TimeoutException, InterruptedException, MemcachedException { + return this.set(key, exp, value, this.opTimeout); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#set(java.lang.String, int, java.lang.Object, long) + */ + @SuppressWarnings("unchecked") + public final boolean set(final String key, final int exp, final Object value, final long timeout) + throws TimeoutException, InterruptedException, MemcachedException { + return this.set(key, exp, value, this.transcoder, timeout); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#set(java.lang.String, int, T, + * net.rubyeye.xmemcached.transcoders.Transcoder) + */ + public final boolean set(final String key, final int exp, final T value, + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException { + return this.set(key, exp, value, transcoder, this.opTimeout); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#add(java.lang.String, int, T, + * net.rubyeye.xmemcached.transcoders.Transcoder, long) + */ + public final boolean add(String key, final int exp, final T value, + final Transcoder transcoder, final long timeout) + throws TimeoutException, InterruptedException, MemcachedException { + key = this.preProcessKey(key); + return this.add0(key, exp, value, transcoder, timeout); + } + + private boolean add0(String key, int exp, T value, Transcoder transcoder, long timeout) + throws InterruptedException, TimeoutException, MemcachedException { + byte[] keyBytes = this.checkStoreArguments(key, exp, value); + return this.sendStoreCommand( + this.commandFactory.createAddCommand(key, keyBytes, exp, value, false, transcoder), + timeout); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#add(java.lang.String, int, java.lang.Object) + */ + public final boolean add(final String key, final int exp, final Object value) + throws TimeoutException, InterruptedException, MemcachedException { + return this.add(key, exp, value, this.opTimeout); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#add(java.lang.String, int, java.lang.Object, long) + */ + @SuppressWarnings("unchecked") + public final boolean add(final String key, final int exp, final Object value, final long timeout) + throws TimeoutException, InterruptedException, MemcachedException { + return this.add(key, exp, value, this.transcoder, timeout); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#add(java.lang.String, int, T, + * net.rubyeye.xmemcached.transcoders.Transcoder) + */ + public final boolean add(final String key, final int exp, final T value, + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException { + return this.add(key, exp, value, transcoder, this.opTimeout); + } + + @SuppressWarnings("unchecked") + public void addWithNoReply(String key, int exp, Object value) + throws InterruptedException, MemcachedException { + this.addWithNoReply(key, exp, value, this.transcoder); + + } + + public void addWithNoReply(String key, int exp, T value, Transcoder transcoder) + throws InterruptedException, MemcachedException { + key = this.preProcessKey(key); + byte[] keyBytes = this.checkStoreArguments(key, exp, value); + try { + this.sendStoreCommand( + this.commandFactory.createAddCommand(key, keyBytes, exp, value, true, transcoder), + this.opTimeout); + } catch (TimeoutException e) { + throw new MemcachedException(e); + } + + } + + @SuppressWarnings("unchecked") + public void replaceWithNoReply(String key, int exp, Object value) + throws InterruptedException, MemcachedException { + this.replaceWithNoReply(key, exp, value, this.transcoder); + + } + + public void replaceWithNoReply(String key, int exp, T value, Transcoder transcoder) + throws InterruptedException, MemcachedException { + key = this.preProcessKey(key); + byte[] keyBytes = this.checkStoreArguments(key, exp, value); + try { + this.sendStoreCommand( + this.commandFactory.createReplaceCommand(key, keyBytes, exp, value, true, transcoder), + this.opTimeout); + } catch (TimeoutException e) { + throw new MemcachedException(e); + } + + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#replace(java.lang.String, int, T, + * net.rubyeye.xmemcached.transcoders.Transcoder, long) + */ + public final boolean replace(String key, final int exp, final T value, + final Transcoder transcoder, final long timeout) + throws TimeoutException, InterruptedException, MemcachedException { + key = this.preProcessKey(key); + byte[] keyBytes = this.checkStoreArguments(key, exp, value); + return this.sendStoreCommand( + this.commandFactory.createReplaceCommand(key, keyBytes, exp, value, false, transcoder), + timeout); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#replace(java.lang.String, int, java.lang.Object) + */ + public final boolean replace(final String key, final int exp, final Object value) + throws TimeoutException, InterruptedException, MemcachedException { + return this.replace(key, exp, value, this.opTimeout); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#replace(java.lang.String, int, java.lang.Object, + * long) + */ + @SuppressWarnings("unchecked") + public final boolean replace(final String key, final int exp, final Object value, + final long timeout) throws TimeoutException, InterruptedException, MemcachedException { + return this.replace(key, exp, value, this.transcoder, timeout); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#replace(java.lang.String, int, T, + * net.rubyeye.xmemcached.transcoders.Transcoder) + */ + public final boolean replace(final String key, final int exp, final T value, + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException { + return this.replace(key, exp, value, transcoder, this.opTimeout); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#append(java.lang.String, java.lang.Object) + */ + public final boolean append(final String key, final Object value) + throws TimeoutException, InterruptedException, MemcachedException { + return this.append(key, value, this.opTimeout); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#append(java.lang.String, java.lang.Object, long) + */ + public final boolean append(String key, final Object value, final long timeout) + throws TimeoutException, InterruptedException, MemcachedException { + key = this.preProcessKey(key); + byte[] keyBytes = this.checkStoreArguments(key, 0, value); + return this.sendStoreCommand( + this.commandFactory.createAppendCommand(key, keyBytes, value, false, this.transcoder), + timeout); + } + + public void appendWithNoReply(String key, Object value) + throws InterruptedException, MemcachedException { + key = this.preProcessKey(key); + byte[] keyBytes = this.checkStoreArguments(key, 0, value); + try { + this.sendStoreCommand( + this.commandFactory.createAppendCommand(key, keyBytes, value, true, this.transcoder), + this.opTimeout); + } catch (TimeoutException e) { + throw new MemcachedException(e); + } + + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#prepend(java.lang.String, java.lang.Object) + */ + public final boolean prepend(final String key, final Object value) + throws TimeoutException, InterruptedException, MemcachedException { + return this.prepend(key, value, this.opTimeout); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#prepend(java.lang.String, java.lang.Object, long) + */ + public final boolean prepend(String key, final Object value, final long timeout) + throws TimeoutException, InterruptedException, MemcachedException { + key = this.preProcessKey(key); + byte[] keyBytes = this.checkStoreArguments(key, 0, value); + return this.sendStoreCommand( + this.commandFactory.createPrependCommand(key, keyBytes, value, false, this.transcoder), + timeout); + } + + public void prependWithNoReply(String key, Object value) + throws InterruptedException, MemcachedException { + key = this.preProcessKey(key); + byte[] keyBytes = this.checkStoreArguments(key, 0, value); + try { + this.sendStoreCommand( + this.commandFactory.createPrependCommand(key, keyBytes, value, true, this.transcoder), + this.opTimeout); + } catch (TimeoutException e) { + throw new MemcachedException(e); + } + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#cas(java.lang.String, int, java.lang.Object, long) + */ + public final boolean cas(final String key, final int exp, final Object value, final long cas) + throws TimeoutException, InterruptedException, MemcachedException { + return this.cas(key, exp, value, this.opTimeout, cas); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#cas(java.lang.String, int, T, + * net.rubyeye.xmemcached.transcoders.Transcoder, long, long) + */ + public final boolean cas(String key, final int exp, final T value, + final Transcoder transcoder, final long timeout, final long cas) + throws TimeoutException, InterruptedException, MemcachedException { + key = this.preProcessKey(key); + byte[] keyBytes = this.checkStoreArguments(key, 0, value); + return this.sendStoreCommand( + this.commandFactory.createCASCommand(key, keyBytes, exp, value, cas, false, transcoder), + timeout); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#cas(java.lang.String, int, java.lang.Object, long, + * long) + */ + @SuppressWarnings("unchecked") + public final boolean cas(final String key, final int exp, final Object value, final long timeout, + final long cas) throws TimeoutException, InterruptedException, MemcachedException { + return this.cas(key, exp, value, this.transcoder, timeout, cas); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#cas(java.lang.String, int, T, + * net.rubyeye.xmemcached.transcoders.Transcoder, long) + */ + public final boolean cas(final String key, final int exp, final T value, + final Transcoder transcoder, final long cas) + throws TimeoutException, InterruptedException, MemcachedException { + return this.cas(key, exp, value, transcoder, this.opTimeout, cas); + } + + private final boolean cas0(final String key, final int exp, GetsResponse getsResponse, + final CASOperation operation, final Transcoder transcoder, byte[] keyBytes, + boolean noreply) throws TimeoutException, InterruptedException, MemcachedException { + if (operation == null) { + throw new IllegalArgumentException("CASOperation could not be null"); + } + if (operation.getMaxTries() < 0) { + throw new IllegalArgumentException("max tries must be greater than 0"); + } + int tryCount = 0; + GetsResponse result = getsResponse; + if (result == null) { + throw new NoValueException("Null GetsResponse for key=" + key); + } + while (tryCount <= operation.getMaxTries() && result != null + && !this.sendStoreCommand(this.commandFactory.createCASCommand(key, keyBytes, exp, + operation.getNewValue(result.getCas(), result.getValue()), result.getCas(), noreply, + transcoder), this.opTimeout) + && !noreply) { + tryCount++; + result = this.gets0(key, keyBytes, transcoder); + if (result == null) { + throw new NoValueException("could not gets the value for Key=" + key + " for cas"); + } + if (tryCount > operation.getMaxTries()) { + throw new TimeoutException("CAS try times is greater than max"); + } + } + return true; + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#cas(java.lang.String, int, + * net.rubyeye.xmemcached.CASOperation, net.rubyeye.xmemcached.transcoders.Transcoder) + */ + public final boolean cas(String key, final int exp, final CASOperation operation, + final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException { + key = this.preProcessKey(key); + byte[] keyBytes = ByteUtils.getBytes(key); + ByteUtils.checkKey(keyBytes); + GetsResponse result = this.gets0(key, keyBytes, transcoder); + return this.cas0(key, exp, result, operation, transcoder, keyBytes, false); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#cas(java.lang.String, int, + * net.rubyeye.xmemcached.GetsResponse, net.rubyeye.xmemcached.CASOperation, + * net.rubyeye.xmemcached.transcoders.Transcoder) + */ + public final boolean cas(String key, final int exp, GetsResponse getsReponse, + final CASOperation operation, final Transcoder transcoder) + throws TimeoutException, InterruptedException, MemcachedException { + key = this.preProcessKey(key); + byte[] keyBytes = ByteUtils.getBytes(key); + ByteUtils.checkKey(keyBytes); + return this.cas0(key, exp, getsReponse, operation, transcoder, keyBytes, false); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#cas(java.lang.String, int, + * net.rubyeye.xmemcached.GetsResponse, net.rubyeye.xmemcached.CASOperation) + */ + @SuppressWarnings("unchecked") + public final boolean cas(final String key, final int exp, GetsResponse getsReponse, + final CASOperation operation) + throws TimeoutException, InterruptedException, MemcachedException { + + return this.cas(key, exp, getsReponse, operation, this.transcoder); + } + + public void casWithNoReply(String key, CASOperation operation) + throws TimeoutException, InterruptedException, MemcachedException { + this.casWithNoReply(key, 0, operation); + } + + public void casWithNoReply(String key, GetsResponse getsResponse, + CASOperation operation) throws TimeoutException, InterruptedException, MemcachedException { + this.casWithNoReply(key, 0, getsResponse, operation); + + } + + @SuppressWarnings("unchecked") + public void casWithNoReply(String key, int exp, CASOperation operation) + throws TimeoutException, InterruptedException, MemcachedException { + key = this.preProcessKey(key); + byte[] keyBytes = ByteUtils.getBytes(key); + GetsResponse result = this.gets0(key, keyBytes, this.transcoder); + this.casWithNoReply(key, exp, result, operation); + + } + + @SuppressWarnings("unchecked") + public void casWithNoReply(String key, int exp, GetsResponse getsReponse, + CASOperation operation) throws TimeoutException, InterruptedException, MemcachedException { + key = this.preProcessKey(key); + byte[] keyBytes = ByteUtils.getBytes(key); + ByteUtils.checkKey(keyBytes); + this.cas0(key, exp, getsReponse, operation, this.transcoder, keyBytes, true); + + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#cas(java.lang.String, + * net.rubyeye.xmemcached.GetsResponse, net.rubyeye.xmemcached.CASOperation) + */ + public final boolean cas(final String key, GetsResponse getsReponse, + final CASOperation operation) + throws TimeoutException, InterruptedException, MemcachedException { + return this.cas(key, 0, getsReponse, operation); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#cas(java.lang.String, int, + * net.rubyeye.xmemcached.CASOperation) + */ + @SuppressWarnings("unchecked") + public final boolean cas(final String key, final int exp, final CASOperation operation) + throws TimeoutException, InterruptedException, MemcachedException { + return this.cas(key, exp, operation, this.transcoder); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#cas(java.lang.String, + * net.rubyeye.xmemcached.CASOperation) + */ + public final boolean cas(final String key, final CASOperation operation) + throws TimeoutException, InterruptedException, MemcachedException { + return this.cas(key, 0, operation); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#delete(java.lang.String, int) + */ + public final boolean delete(final String key, final int time) + throws TimeoutException, InterruptedException, MemcachedException { + return this.delete0(key, time, 0, false, this.opTimeout); + } + + public boolean delete(String key, long opTimeout) + throws TimeoutException, InterruptedException, MemcachedException { + return this.delete0(key, 0, 0, false, opTimeout); + } + + public boolean delete(String key, long cas, long opTimeout) + throws TimeoutException, InterruptedException, MemcachedException { + return this.delete0(key, 0, cas, false, opTimeout); + } + + /** + * Delete key's data item from memcached.This method doesn't wait for reply + * + * @param key + * @param time + * @throws InterruptedException + * @throws MemcachedException + */ + public final void deleteWithNoReply(final String key, final int time) + throws InterruptedException, MemcachedException { + try { + this.delete0(key, time, 0, true, this.opTimeout); + } catch (TimeoutException e) { + throw new MemcachedException(e); + } + } + + public final void deleteWithNoReply(final String key) + throws InterruptedException, MemcachedException { + this.deleteWithNoReply(key, 0); + } + + private boolean delete0(String key, final int time, long cas, boolean noreply, long opTimeout) + throws MemcachedException, InterruptedException, TimeoutException { + key = this.preProcessKey(key); + final byte[] keyBytes = ByteUtils.getBytes(key); + ByteUtils.checkKey(keyBytes); + final Command command = + this.commandFactory.createDeleteCommand(key, keyBytes, time, cas, noreply); + final Session session = this.sendCommand(command); + if (!command.isNoreply()) { + this.latchWait(command, opTimeout, session); + command.getIoBuffer().free(); + this.checkException(command); + if (command.getResult() == null) { + throw new MemcachedException("Operation fail,may be caused by networking or timeout"); + } + } else { + return false; + } + return (Boolean) command.getResult(); + } + + protected void checkException(final Command command) throws MemcachedException { + if (command.getException() != null) { + if (command.getException() instanceof MemcachedException) { + throw (MemcachedException) command.getException(); + } else { + throw new MemcachedException(command.getException()); + } + } + } + + public boolean touch(String key, int exp, long opTimeout) + throws TimeoutException, InterruptedException, MemcachedException { + key = this.preProcessKey(key); + final byte[] keyBytes = ByteUtils.getBytes(key); + ByteUtils.checkKey(keyBytes); + CountDownLatch latch = new CountDownLatch(1); + final Command command = + this.commandFactory.createTouchCommand(key, keyBytes, latch, exp, false); + this.latchWait(command, opTimeout, this.sendCommand(command)); + command.getIoBuffer().free(); + this.checkException(command); + if (command.getResult() == null) { + throw new MemcachedException("Operation fail,may be caused by networking or timeout"); + } + return (Boolean) command.getResult(); + } + + public boolean touch(String key, int exp) + throws TimeoutException, InterruptedException, MemcachedException { + return this.touch(key, exp, this.opTimeout); + } + + @SuppressWarnings("unchecked") + public T getAndTouch(String key, int newExp, long opTimeout) + throws TimeoutException, InterruptedException, MemcachedException { + key = this.preProcessKey(key); + final byte[] keyBytes = ByteUtils.getBytes(key); + ByteUtils.checkKey(keyBytes); + CountDownLatch latch = new CountDownLatch(1); + final Command command = + this.commandFactory.createGetAndTouchCommand(key, keyBytes, latch, newExp, false); + this.latchWait(command, opTimeout, this.sendCommand(command)); + command.getIoBuffer().free(); + this.checkException(command); + CachedData data = (CachedData) command.getResult(); + if (data == null) { + return null; + } + return (T) this.transcoder.decode(data); + } + + @SuppressWarnings("unchecked") + public T getAndTouch(String key, int newExp) + throws TimeoutException, InterruptedException, MemcachedException { + return (T) this.getAndTouch(key, newExp, this.opTimeout); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#incr(java.lang.String, int) + */ + public final long incr(String key, final long delta) + throws TimeoutException, InterruptedException, MemcachedException { + key = this.preProcessKey(key); + return this.sendIncrOrDecrCommand(key, delta, 0, CommandType.INCR, false, this.opTimeout, 0); + } + + public long incr(String key, long delta, long initValue) + throws TimeoutException, InterruptedException, MemcachedException { + key = this.preProcessKey(key); + return this.sendIncrOrDecrCommand(key, delta, initValue, CommandType.INCR, false, + this.opTimeout, 0); + } + + public long incr(String key, long delta, long initValue, long timeout) + throws TimeoutException, InterruptedException, MemcachedException { + key = this.preProcessKey(key); + return this.sendIncrOrDecrCommand(key, delta, initValue, CommandType.INCR, false, timeout, 0); + } + + public long incr(String key, long delta, long initValue, long timeout, int exp) + throws TimeoutException, InterruptedException, MemcachedException { + key = this.preProcessKey(key); + return this.sendIncrOrDecrCommand(key, delta, initValue, CommandType.INCR, false, timeout, exp); + } + + public final void incrWithNoReply(String key, long delta) + throws InterruptedException, MemcachedException { + key = this.preProcessKey(key); + try { + this.sendIncrOrDecrCommand(key, delta, 0, CommandType.INCR, true, this.opTimeout, 0); + } catch (TimeoutException e) { + throw new MemcachedException(e); + } + } + + public final void decrWithNoReply(String key, final long delta) + throws InterruptedException, MemcachedException { + key = this.preProcessKey(key); + try { + this.sendIncrOrDecrCommand(key, delta, 0, CommandType.DECR, true, this.opTimeout, 0); + } catch (TimeoutException e) { + throw new MemcachedException(e); + } + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#decr(java.lang.String, int) + */ + public final long decr(String key, final long delta) + throws TimeoutException, InterruptedException, MemcachedException { + key = this.preProcessKey(key); + return this.sendIncrOrDecrCommand(key, delta, 0, CommandType.DECR, false, this.opTimeout, 0); + } + + public long decr(String key, long delta, long initValue) + throws TimeoutException, InterruptedException, MemcachedException { + key = this.preProcessKey(key); + return this.sendIncrOrDecrCommand(key, delta, initValue, CommandType.DECR, false, + this.opTimeout, 0); + } + + public long decr(String key, long delta, long initValue, long timeout) + throws TimeoutException, InterruptedException, MemcachedException { + key = this.preProcessKey(key); + return this.sendIncrOrDecrCommand(key, delta, initValue, CommandType.DECR, false, timeout, 0); + } + + public long decr(String key, long delta, long initValue, long timeout, int exp) + throws TimeoutException, InterruptedException, MemcachedException { + key = this.preProcessKey(key); + return this.sendIncrOrDecrCommand(key, delta, initValue, CommandType.DECR, false, timeout, exp); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#flushAll() + */ + public final void flushAll() throws TimeoutException, InterruptedException, MemcachedException { + this.flushAll(this.opTimeout); + } + + public void flushAllWithNoReply() throws InterruptedException, MemcachedException { + try { + this.flushAllMemcachedServers(this.opTimeout, true, 0); + } catch (TimeoutException e) { + throw new MemcachedException(e); + } + } + + public void flushAllWithNoReply(int exptime) throws InterruptedException, MemcachedException { + try { + this.flushAllMemcachedServers(this.opTimeout, true, exptime); + } catch (TimeoutException e) { + throw new MemcachedException(e); + } + } + + public void flushAllWithNoReply(InetSocketAddress address) + throws MemcachedException, InterruptedException { + try { + this.flushSpecialMemcachedServer(address, this.opTimeout, true, 0); + } catch (TimeoutException e) { + throw new MemcachedException(e); + } + } + + public void flushAllWithNoReply(InetSocketAddress address, int exptime) + throws MemcachedException, InterruptedException { + try { + this.flushSpecialMemcachedServer(address, this.opTimeout, true, exptime); + } catch (TimeoutException e) { + throw new MemcachedException(e); + } + } + + public final void flushAll(int exptime, long timeout) + throws TimeoutException, InterruptedException, MemcachedException { + this.flushAllMemcachedServers(timeout, false, exptime); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#flushAll(long) + */ + public final void flushAll(long timeout) + throws TimeoutException, InterruptedException, MemcachedException { + this.flushAllMemcachedServers(timeout, false, 0); + } + + private void flushAllMemcachedServers(long timeout, boolean noreply, int exptime) + throws MemcachedException, InterruptedException, TimeoutException { + final Collection sessions = this.connector.getSessionSet(); + CountDownLatch latch = new CountDownLatch(sessions.size()); + List commands = new ArrayList(sessions.size()); + for (Session session : sessions) { + if (session != null && !session.isClosed()) { + Command command = this.commandFactory.createFlushAllCommand(latch, exptime, noreply); + + session.write(command); + } else { + latch.countDown(); + } + } + if (!noreply) { + if (!latch.await(timeout, TimeUnit.MILLISECONDS)) { + for (Command cmd : commands) { + cmd.cancel(); + } + throw new TimeoutException("Timed out waiting for operation"); + } + } + } + + public void setLoggingLevelVerbosity(InetSocketAddress address, int level) + throws TimeoutException, InterruptedException, MemcachedException { + this.setMemcachedLoggingLevel(address, level, false); + + } + + private void setMemcachedLoggingLevel(InetSocketAddress address, int level, boolean noreply) + throws MemcachedException, InterruptedException, TimeoutException { + if (address == null) { + throw new IllegalArgumentException("Null adderss"); + } + CountDownLatch latch = new CountDownLatch(1); + + Queue sessionQueue = this.connector.getSessionByAddress(address); + if (sessionQueue == null || sessionQueue.peek() == null) { + throw new MemcachedException( + "could not find session for " + SystemUtils.getRawAddress(address) + ":" + + address.getPort() + ",maybe it have not been connected"); + } + + Command command = this.commandFactory.createVerbosityCommand(latch, level, noreply); + final Session session = sessionQueue.peek(); + session.write(command); + if (!noreply) { + this.latchWait(command, this.opTimeout, session); + } + } + + public void setLoggingLevelVerbosityWithNoReply(InetSocketAddress address, int level) + throws InterruptedException, MemcachedException { + try { + this.setMemcachedLoggingLevel(address, level, true); + } catch (TimeoutException e) { + throw new MemcachedException(e); + } + + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#flushAll(java.net. InetSocketAddress ) + */ + public final void flushAll(InetSocketAddress address) + throws MemcachedException, InterruptedException, TimeoutException { + this.flushAll(address, this.opTimeout); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#flushAll(java.net. InetSocketAddress , long) + */ + public final void flushAll(InetSocketAddress address, long timeout) + throws MemcachedException, InterruptedException, TimeoutException { + this.flushSpecialMemcachedServer(address, timeout, false, 0); + } + + public final void flushAll(InetSocketAddress address, long timeout, int exptime) + throws MemcachedException, InterruptedException, TimeoutException { + this.flushSpecialMemcachedServer(address, timeout, false, exptime); + } + + private void flushSpecialMemcachedServer(InetSocketAddress address, long timeout, boolean noreply, + int exptime) throws MemcachedException, InterruptedException, TimeoutException { + if (address == null) { + throw new IllegalArgumentException("Null adderss"); + } + CountDownLatch latch = new CountDownLatch(1); + + Queue sessionQueue = this.connector.getSessionByAddress(address); + if (sessionQueue == null || sessionQueue.peek() == null) { + throw new MemcachedException( + "could not find session for " + SystemUtils.getRawAddress(address) + ":" + + address.getPort() + ",maybe it have not been connected"); + } + Command command = this.commandFactory.createFlushAllCommand(latch, exptime, noreply); + final Session session = sessionQueue.peek(); + session.write(command); + if (!noreply) { + this.latchWait(command, timeout, session); + } + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#flushAll(java.lang.String) + */ + public final void flushAll(String host) + throws TimeoutException, InterruptedException, MemcachedException { + this.flushAll(AddrUtil.getOneAddress(host), this.opTimeout); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#stats(java.net.InetSocketAddress) + */ + public final Map stats(InetSocketAddress address) + throws MemcachedException, InterruptedException, TimeoutException { + return this.stats(address, this.opTimeout); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#stats(java.net.InetSocketAddress, long) + */ + @SuppressWarnings("unchecked") + public final Map stats(InetSocketAddress address, long timeout) + throws MemcachedException, InterruptedException, TimeoutException { + if (address == null) { + throw new IllegalArgumentException("Null inetSocketAddress"); + } + CountDownLatch latch = new CountDownLatch(1); + + Queue sessionQueue = this.connector.getSessionByAddress(address); + if (sessionQueue == null || sessionQueue.peek() == null) { + throw new MemcachedException( + "could not find session for " + SystemUtils.getRawAddress(address) + ":" + + address.getPort() + ",maybe it have not been connected"); + } + Command command = this.commandFactory.createStatsCommand(address, latch, null); + final Session session = sessionQueue.peek(); + session.write(command); + this.latchWait(command, timeout, session); + return (Map) command.getResult(); + } + + public final Map> getStats() + throws MemcachedException, InterruptedException, TimeoutException { + return this.getStats(this.opTimeout); + } + + public final Map> getStatsByItem(String itemName) + throws MemcachedException, InterruptedException, TimeoutException { + return this.getStatsByItem(itemName, this.opTimeout); + } + + @SuppressWarnings("unchecked") + public final Map> getStatsByItem(String itemName, + long timeout) throws MemcachedException, InterruptedException, TimeoutException { + final Set sessionSet = this.connector.getSessionSet(); + final Map> collectResult = + new HashMap>(); + if (sessionSet.size() == 0) { + return collectResult; + } + final CountDownLatch latch = new CountDownLatch(sessionSet.size()); + List commands = new ArrayList(sessionSet.size()); + for (Session session : sessionSet) { + Command command = + this.commandFactory.createStatsCommand(session.getRemoteSocketAddress(), latch, itemName); + + session.write(command); + commands.add(command); + + } + if (!latch.await(timeout, TimeUnit.MILLISECONDS)) { + for (Command command : commands) { + command.cancel(); + } + throw new TimeoutException("Timed out waiting for operation"); + } + for (Command command : commands) { + this.checkException(command); + collectResult.put(((ServerAddressAware) command).getServer(), + (Map) command.getResult()); + } + return collectResult; + } + + public final Map getVersions() + throws TimeoutException, InterruptedException, MemcachedException { + return this.getVersions(this.opTimeout); + } + + public final Map getVersions(long timeout) + throws TimeoutException, InterruptedException, MemcachedException { + final Set sessionSet = this.connector.getSessionSet(); + Map collectResult = new HashMap(); + if (sessionSet.size() == 0) { + return collectResult; + } + final CountDownLatch latch = new CountDownLatch(sessionSet.size()); + List commands = new ArrayList(sessionSet.size()); + for (Session session : sessionSet) { + Command command = + this.commandFactory.createVersionCommand(latch, session.getRemoteSocketAddress()); + session.write(command); + commands.add(command); + + } + + if (!latch.await(timeout, TimeUnit.MILLISECONDS)) { + for (Command command : commands) { + command.cancel(); + } + throw new TimeoutException("Timed out waiting for operation"); + } + for (Command command : commands) { + this.checkException(command); + collectResult.put(((ServerAddressAware) command).getServer(), (String) command.getResult()); + } + return collectResult; + } + + public Map> getStats(long timeout) + throws MemcachedException, InterruptedException, TimeoutException { + return this.getStatsByItem(null, timeout); + } + + /** + * For subclass override. + */ + protected void shutdown0() { + + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#shutdown() + */ + public final void shutdown() throws IOException { + if (this.shutdown) { + return; + } + this.shutdown0(); + this.shutdown = true; + this.connector.shuttingDown(); + this.connector.quitAllSessions(); + this.connector.stop(); + this.memcachedHandler.stop(); + XMemcachedMbeanServer.getInstance().shutdown(); + if (AddrUtil.isEnableShutDownHook() && !this.isHutdownHookCalled) { + try { + Runtime.getRuntime().removeShutdownHook(this.shutdownHookThread); + } catch (Exception e) { + // ignore; + } + } + } + + private long sendIncrOrDecrCommand(final String key, final long delta, long initValue, + final CommandType cmdType, boolean noreply, long operationTimeout, int exp) + throws InterruptedException, TimeoutException, MemcachedException { + final byte[] keyBytes = ByteUtils.getBytes(key); + ByteUtils.checkKey(keyBytes); + final Command command = this.commandFactory.createIncrDecrCommand(key, keyBytes, delta, + initValue, exp, cmdType, noreply); + final Session session = this.sendCommand(command); + if (!command.isNoreply()) { + this.latchWait(command, operationTimeout, session); + command.getIoBuffer().free(); + this.checkException(command); + if (command.getResult() == null) { + throw new MemcachedException("Operation fail,may be caused by networking or timeout"); + } + final Object result = command.getResult(); + if (result instanceof String) { + if (((String) result).equals("NOT_FOUND")) { + if (this.add0(key, exp, String.valueOf(initValue), this.transcoder, this.opTimeout)) { + return initValue; + } else { + return this.sendIncrOrDecrCommand(key, delta, initValue, cmdType, noreply, + operationTimeout, exp); + } + } else { + throw new MemcachedException( + "Unknown result type for incr/decr:" + result.getClass() + ",result=" + result); + } + } else { + return (Long) command.getResult(); + } + } else { + return -1; + } + } + + public void setConnectionPoolSize(int poolSize) { + if (!this.shutdown && this.getAvaliableServers().size() > 0) { + throw new IllegalStateException("Xmemcached client has been started"); + } + if (poolSize <= 0) { + throw new IllegalArgumentException("poolSize<=0"); + } + this.connectionPoolSize = poolSize; + this.connector.setConnectionPoolSize(poolSize); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#delete(java.lang.String) + */ + public final boolean delete(final String key) + throws TimeoutException, InterruptedException, MemcachedException { + return this.delete(key, 0); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#getTranscoder() + */ + @SuppressWarnings("unchecked") + public final Transcoder getTranscoder() { + return this.transcoder; + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClient#setTranscoder(net.rubyeye. xmemcached + * .transcoders.Transcoder) + */ + @SuppressWarnings("unchecked") + public final void setTranscoder(final Transcoder transcoder) { + this.transcoder = transcoder; + } + + private final boolean sendStoreCommand(Command command, long timeout) + throws InterruptedException, TimeoutException, MemcachedException { + + final Session session = this.sendCommand(command); + if (!command.isNoreply()) { + this.latchWait(command, timeout, session); + command.getIoBuffer().free(); + this.checkException(command); + if (command.getResult() == null) { + throw new MemcachedException("Operation fail,may be caused by networking or timeout"); + } + } else { + return false; + } + return (Boolean) command.getResult(); + } + + private static final String CONTINUOUS_TIMEOUT_COUNTER = "ContinuousTimeouts"; + + protected void latchWait(final Command cmd, final long timeout, final Session session) + throws InterruptedException, TimeoutException { + if (cmd.getLatch().await(timeout, TimeUnit.MILLISECONDS)) { + AtomicInteger counter = this.getContinuousTimeoutCounter(session); + // reset counter. + if (counter.get() > 0) { + counter.set(0); + } + } else { + cmd.cancel(); + AtomicInteger counter = this.getContinuousTimeoutCounter(session); + if (counter.incrementAndGet() > this.timeoutExceptionThreshold) { + log.warn(session + " exceeded continuous timeout threshold,we will close it."); + try { + // reset counter. + counter.set(0); + session.close(); + } catch (Exception e) { + // ignore it. + } + } + throw new TimeoutException("Timed out(" + timeout + + " milliseconds) waiting for operation while connected to " + session); + } + } + + private AtomicInteger getContinuousTimeoutCounter(final Session session) { + AtomicInteger counter = (AtomicInteger) session.getAttribute(CONTINUOUS_TIMEOUT_COUNTER); + if (counter == null) { + counter = new AtomicInteger(0); + AtomicInteger oldCounter = + (AtomicInteger) session.setAttributeIfAbsent(CONTINUOUS_TIMEOUT_COUNTER, counter); + if (oldCounter != null) { + counter = oldCounter; + } + } + return counter; + } + + /** + * Use getAvailableServers() instead + * + * @deprecated + * @see MemcachedClient#getAvailableServers() + */ + @Deprecated + public final Collection getAvaliableServers() { + return this.getAvailableServers(); + } + + public Collection getAvailableServers() { + Set sessionSet = this.connector.getSessionSet(); + Set result = new HashSet(); + for (Session session : sessionSet) { + result.add(session.getRemoteSocketAddress()); + } + return Collections.unmodifiableSet(result); + } + + public final int getConnectionSizeBySocketAddress(InetSocketAddress address) { + Queue sessionList = this.connector.getSessionByAddress(address); + return sessionList == null ? 0 : sessionList.size(); + } + + public void addStateListener(MemcachedClientStateListener listener) { + MemcachedClientStateListenerAdapter adapter = + new MemcachedClientStateListenerAdapter(listener, this); + this.stateListenerAdapters.add(adapter); + this.connector.addStateListener(adapter); + } + + public Collection getStateListeners() { + final List result = + new ArrayList(this.stateListenerAdapters.size()); + for (MemcachedClientStateListenerAdapter adapter : this.stateListenerAdapters) { + result.add(adapter.getMemcachedClientStateListener()); + } + return result; + } + + public void setPrimitiveAsString(boolean primitiveAsString) { + this.transcoder.setPrimitiveAsString(primitiveAsString); + } + + public void removeStateListener(MemcachedClientStateListener listener) { + for (MemcachedClientStateListenerAdapter adapter : this.stateListenerAdapters) { + if (adapter.getMemcachedClientStateListener().equals(listener)) { + this.stateListenerAdapters.remove(adapter); + this.connector.removeStateListener(adapter); + } + } + } + + public Protocol getProtocol() { + return this.commandFactory.getProtocol(); + } + + public boolean isSanitizeKeys() { + return this.sanitizeKeys; + } + + public void setSanitizeKeys(boolean sanitizeKeys) { + this.sanitizeKeys = sanitizeKeys; + } + + private String decodeKey(String key) + throws MemcachedException, InterruptedException, TimeoutException { + try { + key = this.sanitizeKeys ? URLDecoder.decode(key, "UTF-8") : key; + } catch (UnsupportedEncodingException e) { + throw new MemcachedException("Unsupport encoding utf-8 when decodeKey", e); + } + String ns = NAMESPACE_LOCAL.get(); + if (ns != null && ns.trim().length() > 0) { + String nsValue = this.getNamespace(ns); + try { + if (nsValue != null && key.startsWith(nsValue)) { + // The extra length of ':' + key = key.substring(nsValue.length() + 1); + } else { + return null; + } + } catch (Exception e) { + throw new MemcachedException("Exception occured when decode key.", e); + } + } + return key; + } + + private String preProcessKey(String key) throws MemcachedException, InterruptedException { + key = this.keyProvider.process(key); + try { + key = this.sanitizeKeys ? URLEncoder.encode(key, "UTF-8") : key; + } catch (UnsupportedEncodingException e) { + throw new MemcachedException("Unsupport encoding utf-8 when sanitize key", e); + } + String ns = NAMESPACE_LOCAL.get(); + if (ns != null && ns.trim().length() > 0) { + try { + key = this.getNamespace(ns) + ":" + key; + } catch (TimeoutException e) { + throw new MemcachedException("Timeout occured when gettting namespace value.", e); + } + } + return key; + } + + public void invalidateNamespace(String ns, long opTimeout) + throws MemcachedException, InterruptedException, TimeoutException { + String key = this.getNSKey(ns); + this.incr(key, 1, System.currentTimeMillis(), opTimeout); + } + + public void invalidateNamespace(String ns) + throws MemcachedException, InterruptedException, TimeoutException { + this.invalidateNamespace(ns, this.opTimeout); + } + + /** + * Returns the real namespace of ns. + * + * @param ns + * @return + * @throws TimeoutException + * @throws InterruptedException + * @throws MemcachedException + */ + public String getNamespace(String ns) + throws TimeoutException, InterruptedException, MemcachedException { + String key = this.keyProvider.process(this.getNSKey(ns)); + byte[] keyBytes = ByteUtils.getBytes(key); + ByteUtils.checkKey(keyBytes); + Object item = this.fetch0(key, keyBytes, CommandType.GET_ONE, this.opTimeout, this.transcoder); + while (item == null) { + item = String.valueOf(System.nanoTime()); + boolean added = this.add0(key, 0, item, this.transcoder, this.opTimeout); + if (!added) { + item = this.fetch0(key, keyBytes, CommandType.GET_ONE, this.opTimeout, this.transcoder); + } + } + String namespace = item.toString(); + if (!ByteUtils.isNumber(namespace)) { + throw new IllegalStateException( + "Namespace key already has value.The key is:" + key + ",and the value is:" + namespace); + } + return namespace; + } + + private String getNSKey(String ns) { + String key = "namespace:" + ns; + return key; + } + + public Counter getCounter(String key, long initialValue) { + return new Counter(this, key, initialValue); + } + + public Counter getCounter(String key) { + return new Counter(this, key, 0); + } + + /** + * @deprecated memcached 1.6.x will remove cachedump stats command,so this method will be removed + * in the future + */ + @Deprecated + @SuppressWarnings("unchecked") + public KeyIterator getKeyIterator(InetSocketAddress address) + throws MemcachedException, TimeoutException, InterruptedException { + if (address == null) { + throw new IllegalArgumentException("null address"); + } + Queue sessions = this.connector.getSessionByAddress(address); + if (sessions == null || sessions.size() == 0) { + throw new MemcachedException( + "The special memcached server has not been connected," + address); + } + Session session = sessions.peek(); + CountDownLatch latch = new CountDownLatch(1); + Command command = + this.commandFactory.createStatsCommand(session.getRemoteSocketAddress(), latch, "items"); + session.write(command); + if (!latch.await(5000, TimeUnit.MILLISECONDS)) { + throw new TimeoutException("Operation timeout"); + } + if (command.getException() != null) { + if (command.getException() instanceof MemcachedException) { + throw (MemcachedException) command.getException(); + } else { + throw new MemcachedException("stats items failed", command.getException()); + } + } + Map result = (Map) command.getResult(); + LinkedList itemNumberList = new LinkedList(); + for (Map.Entry entry : result.entrySet()) { + final String key = entry.getKey(); + final String[] keys = key.split(":"); + if (keys.length == 3 && keys[2].equals("number") && keys[0].equals("items")) { + // has items,then add it to itemNumberList + if (Integer.parseInt(entry.getValue()) > 0) { + itemNumberList.add(Integer.parseInt(keys[1])); + } + } + } + return new KeyIteratorImpl(itemNumberList, this, address); + } + + public void setEnableHealSession(boolean enableHealSession) { + if (this.connector != null) { + this.connector.setEnableHealSession(enableHealSession); + } else { + throw new IllegalStateException("The client has not been started."); + } + } + + public void setFailureMode(boolean failureMode) { + this.failureMode = failureMode; + if (this.sessionLocator != null) { + this.sessionLocator.setFailureMode(failureMode); + } + if (this.connector != null) { + this.connector.setFailureMode(failureMode); + } + } + + public boolean isFailureMode() { + return this.failureMode; + } + + public Queue getReconnectRequestQueue() { + return this.connector != null ? this.connector.getReconnectRequestQueue() : null; + } } diff --git a/src/main/java/net/rubyeye/xmemcached/XMemcachedClientBuilder.java b/src/main/java/net/rubyeye/xmemcached/XMemcachedClientBuilder.java index 8b106b9e5..f0fb77685 100644 --- a/src/main/java/net/rubyeye/xmemcached/XMemcachedClientBuilder.java +++ b/src/main/java/net/rubyeye/xmemcached/XMemcachedClientBuilder.java @@ -1,449 +1,425 @@ -package net.rubyeye.xmemcached; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import net.rubyeye.xmemcached.auth.AuthInfo; -import net.rubyeye.xmemcached.buffer.BufferAllocator; -import net.rubyeye.xmemcached.buffer.SimpleBufferAllocator; -import net.rubyeye.xmemcached.command.TextCommandFactory; -import net.rubyeye.xmemcached.impl.ArrayMemcachedSessionLocator; -import net.rubyeye.xmemcached.impl.DefaultKeyProvider; -import net.rubyeye.xmemcached.impl.RandomMemcachedSessionLocaltor; -import net.rubyeye.xmemcached.transcoders.SerializingTranscoder; -import net.rubyeye.xmemcached.transcoders.Transcoder; -import net.rubyeye.xmemcached.utils.AddrUtil; -import net.rubyeye.xmemcached.utils.Protocol; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.code.yanf4j.config.Configuration; -import com.google.code.yanf4j.core.SocketOption; -import com.google.code.yanf4j.core.impl.StandardSocketOption; - -/** - * Builder pattern.Configure XmemcachedClient's options,then build it - * - * @author dennis - * - */ -public class XMemcachedClientBuilder implements MemcachedClientBuilder { - - private static final Logger log = LoggerFactory - .getLogger(XMemcachedClientBuilder.class); - - protected MemcachedSessionLocator sessionLocator = new ArrayMemcachedSessionLocator(); - protected BufferAllocator bufferAllocator = new SimpleBufferAllocator(); - protected Configuration configuration = getDefaultConfiguration(); - protected Map addressMap = new LinkedHashMap(); - - protected int[] weights; - - protected long connectTimeout = MemcachedClient.DEFAULT_CONNECT_TIMEOUT; - - protected int connectionPoolSize = MemcachedClient.DEFAULT_CONNECTION_POOL_SIZE; - - @SuppressWarnings("unchecked") - protected final Map socketOptions = getDefaultSocketOptions(); - - protected List stateListeners = new ArrayList(); - - protected Map authInfoMap = new HashMap(); - - protected String name; - - protected boolean failureMode; - - protected boolean sanitizeKeys; - - protected KeyProvider keyProvider = DefaultKeyProvider.INSTANCE; - - protected int maxQueuedNoReplyOperations = MemcachedClient.DEFAULT_MAX_QUEUED_NOPS; - - protected long healSessionInterval = MemcachedClient.DEFAULT_HEAL_SESSION_INTERVAL; - - protected boolean enableHealSession = true; - - protected long opTimeout = MemcachedClient.DEFAULT_OP_TIMEOUT; - - public long getOpTimeout() { - return opTimeout; - } - - public void setOpTimeout(long opTimeout) { - if (opTimeout <= 0) - throw new IllegalArgumentException( - "Invalid opTimeout value:" + opTimeout); - this.opTimeout = opTimeout; - } - - public int getMaxQueuedNoReplyOperations() { - return maxQueuedNoReplyOperations; - } - - public long getHealSessionInterval() { - return healSessionInterval; - } - - public void setHealSessionInterval(long healSessionInterval) { - this.healSessionInterval = healSessionInterval; - } - - public boolean isEnableHealSession() { - return enableHealSession; - } - - public void setEnableHealSession(boolean enableHealSession) { - this.enableHealSession = enableHealSession; - } - - /** - * Set max queued noreply operations number - * - * @see MemcachedClient#DEFAULT_MAX_QUEUED_NOPS - * @param maxQueuedNoReplyOperations - * @since 1.3.8 - */ - public void setMaxQueuedNoReplyOperations(int maxQueuedNoReplyOperations) { - this.maxQueuedNoReplyOperations = maxQueuedNoReplyOperations; - } - - public void setSanitizeKeys(boolean sanitizeKeys) { - this.sanitizeKeys = sanitizeKeys; - } - - public void addStateListener(MemcachedClientStateListener stateListener) { - this.stateListeners.add(stateListener); - } - - @SuppressWarnings("unchecked") - public void setSocketOption(SocketOption socketOption, Object value) { - if (socketOption == null) { - throw new NullPointerException("Null socketOption"); - } - if (value == null) { - throw new NullPointerException("Null value"); - } - if (!socketOption.type().equals(value.getClass())) { - throw new IllegalArgumentException("Expected " - + socketOption.type().getSimpleName() + " value,but givend " - + value.getClass().getSimpleName()); - } - this.socketOptions.put(socketOption, value); - } - - @SuppressWarnings("unchecked") - public Map getSocketOptions() { - return this.socketOptions; - } - - public final void setConnectionPoolSize(int poolSize) { - if (this.connectionPoolSize <= 0) { - throw new IllegalArgumentException("poolSize<=0"); - } - this.connectionPoolSize = poolSize; - } - - public void removeStateListener( - MemcachedClientStateListener stateListener) { - this.stateListeners.remove(stateListener); - } - - public long getConnectTimeout() { - return connectTimeout; - } - - public void setConnectTimeout(long connectTimeout) { - this.connectTimeout = connectTimeout; - } - - public void setStateListeners( - List stateListeners) { - if (stateListeners == null) { - throw new IllegalArgumentException("Null state listeners"); - } - this.stateListeners = stateListeners; - } - - protected CommandFactory commandFactory = new TextCommandFactory(); - - @SuppressWarnings("unchecked") - public static final Map getDefaultSocketOptions() { - Map map = new HashMap(); - map.put(StandardSocketOption.TCP_NODELAY, - MemcachedClient.DEFAULT_TCP_NO_DELAY); - map.put(StandardSocketOption.SO_RCVBUF, - MemcachedClient.DEFAULT_TCP_RECV_BUFF_SIZE); - map.put(StandardSocketOption.SO_KEEPALIVE, - MemcachedClient.DEFAULT_TCP_KEEPLIVE); - map.put(StandardSocketOption.SO_SNDBUF, - MemcachedClient.DEFAULT_TCP_SEND_BUFF_SIZE); - map.put(StandardSocketOption.SO_LINGER, 0); - map.put(StandardSocketOption.SO_REUSEADDR, true); - return map; - } - - public static final Configuration getDefaultConfiguration() { - final Configuration configuration = new Configuration(); - configuration.setSessionReadBufferSize( - MemcachedClient.DEFAULT_SESSION_READ_BUFF_SIZE); - configuration - .setReadThreadCount(MemcachedClient.DEFAULT_READ_THREAD_COUNT); - configuration.setSessionIdleTimeout( - MemcachedClient.DEFAULT_SESSION_IDLE_TIMEOUT); - configuration.setWriteThreadCount(0); - return configuration; - } - - public boolean isFailureMode() { - return this.failureMode; - } - - public void setFailureMode(boolean failureMode) { - this.failureMode = failureMode; - } - - public final CommandFactory getCommandFactory() { - return this.commandFactory; - } - - public final void setCommandFactory(CommandFactory commandFactory) { - this.commandFactory = commandFactory; - } - - @SuppressWarnings({"rawtypes"}) - protected Transcoder transcoder = new SerializingTranscoder(); - - public XMemcachedClientBuilder(String addressList) { - this(AddrUtil.getAddresses(addressList)); - } - - public XMemcachedClientBuilder(List addressList) { - if (addressList != null) { - for (InetSocketAddress addr : addressList) { - this.addressMap.put(addr, null); - } - } - } - - public XMemcachedClientBuilder(List addressList, - int[] weights) { - if (addressList != null) { - for (InetSocketAddress addr : addressList) { - this.addressMap.put(addr, null); - } - } - this.weights = weights; - } - - public XMemcachedClientBuilder( - Map addressMap) { - this.addressMap = addressMap; - } - - public XMemcachedClientBuilder( - Map addressMap, - int[] weights) { - this.addressMap = addressMap; - this.weights = weights; - } - - public XMemcachedClientBuilder() { - this((Map) null); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClientBuilder#getSessionLocator() - */ - public MemcachedSessionLocator getSessionLocator() { - return this.sessionLocator; - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClientBuilder#setSessionLocator(net. - * rubyeye .xmemcached.MemcachedSessionLocator) - */ - public void setSessionLocator(MemcachedSessionLocator sessionLocator) { - if (sessionLocator == null) { - throw new IllegalArgumentException("Null SessionLocator"); - } - this.sessionLocator = sessionLocator; - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClientBuilder#getBufferAllocator() - */ - public BufferAllocator getBufferAllocator() { - return this.bufferAllocator; - } - - /* - * (non-Javadoc) - * - * @see - * net.rubyeye.xmemcached.MemcachedClientBuilder#setBufferAllocator(net. - * rubyeye.xmemcached.buffer.BufferAllocator) - */ - public void setBufferAllocator(BufferAllocator bufferAllocator) { - if (bufferAllocator == null) { - throw new IllegalArgumentException("Null bufferAllocator"); - } - this.bufferAllocator = bufferAllocator; - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClientBuilder#getConfiguration() - */ - public Configuration getConfiguration() { - return this.configuration; - } - - /* - * (non-Javadoc) - * - * @see - * net.rubyeye.xmemcached.MemcachedClientBuilder#setConfiguration(com.google - * .code.yanf4j.config.Configuration) - */ - public void setConfiguration(Configuration configuration) { - this.configuration = configuration; - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClientBuilder#build() - */ - public MemcachedClient build() throws IOException { - XMemcachedClient memcachedClient; - // kestrel protocol use random session locator. - if (this.commandFactory.getProtocol() == Protocol.Kestrel) { - if (!(this.sessionLocator instanceof RandomMemcachedSessionLocaltor)) { - log.warn( - "Recommend to use `net.rubyeye.xmemcached.impl.RandomMemcachedSessionLocaltor` as session locator for kestrel protocol."); - } - } - if (this.weights == null) { - memcachedClient = new XMemcachedClient(this.sessionLocator, - this.bufferAllocator, this.configuration, - this.socketOptions, this.commandFactory, this.transcoder, - this.addressMap, this.stateListeners, this.authInfoMap, - this.connectionPoolSize, this.connectTimeout, this.name, - this.failureMode); - - } else { - if (this.addressMap == null) { - throw new IllegalArgumentException("Null Address map"); - } - if (this.addressMap.size() > this.weights.length) { - throw new IllegalArgumentException( - "Weights Array's length is less than server's number"); - } - memcachedClient = new XMemcachedClient(this.sessionLocator, - this.bufferAllocator, this.configuration, - this.socketOptions, this.commandFactory, this.transcoder, - this.addressMap, this.weights, this.stateListeners, - this.authInfoMap, this.connectionPoolSize, - this.connectTimeout, this.name, this.failureMode); - } - this.configureClient(memcachedClient); - return memcachedClient; - } - - protected void configureClient(XMemcachedClient memcachedClient) { - if (this.commandFactory.getProtocol() == Protocol.Kestrel) { - memcachedClient.setOptimizeGet(false); - } - memcachedClient.setConnectTimeout(connectTimeout); - memcachedClient.setSanitizeKeys(sanitizeKeys); - memcachedClient.setKeyProvider(this.keyProvider); - memcachedClient.setOpTimeout(this.opTimeout); - memcachedClient.setHealSessionInterval(this.healSessionInterval); - memcachedClient.setEnableHealSession(this.enableHealSession); - memcachedClient - .setMaxQueuedNoReplyOperations(this.maxQueuedNoReplyOperations); - } - - @SuppressWarnings("rawtypes") - public Transcoder getTranscoder() { - return this.transcoder; - } - - /* - * (non-Javadoc) - * - * @see - * net.rubyeye.xmemcached.MemcachedClientBuilder#setTranscoder(transcoder) - */ - public void setTranscoder(Transcoder transcoder) { - if (transcoder == null) { - throw new IllegalArgumentException("Null Transcoder"); - } - this.transcoder = transcoder; - } - - public Map getAuthInfoMap() { - return this.authInfoMap; - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClientBuilder#setKeyProvider() - */ - public void setKeyProvider(KeyProvider keyProvider) { - if (keyProvider == null) - throw new IllegalArgumentException("null key provider"); - this.keyProvider = keyProvider; - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClientBuilder#addAuthInfo() - */ - public void addAuthInfo(InetSocketAddress address, AuthInfo authInfo) { - this.authInfoMap.put(address, authInfo); - } - - public void removeAuthInfo(InetSocketAddress address) { - this.authInfoMap.remove(address); - } - - public void setAuthInfoMap(Map authInfoMap) { - this.authInfoMap = authInfoMap; - } - - public String getName() { - return this.name; - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.MemcachedClientBuilder#setName() - */ - public void setName(String name) { - this.name = name; - - } - - public void setSelectorPoolSize(int selectorPoolSize) { - getConfiguration().setSelectorPoolSize(selectorPoolSize); - } - -} +package net.rubyeye.xmemcached; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import net.rubyeye.xmemcached.auth.AuthInfo; +import net.rubyeye.xmemcached.buffer.BufferAllocator; +import net.rubyeye.xmemcached.buffer.SimpleBufferAllocator; +import net.rubyeye.xmemcached.command.TextCommandFactory; +import net.rubyeye.xmemcached.impl.ArrayMemcachedSessionLocator; +import net.rubyeye.xmemcached.impl.DefaultKeyProvider; +import net.rubyeye.xmemcached.impl.RandomMemcachedSessionLocaltor; +import net.rubyeye.xmemcached.transcoders.SerializingTranscoder; +import net.rubyeye.xmemcached.transcoders.Transcoder; +import net.rubyeye.xmemcached.utils.AddrUtil; +import net.rubyeye.xmemcached.utils.Protocol; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.google.code.yanf4j.config.Configuration; +import com.google.code.yanf4j.core.SocketOption; +import com.google.code.yanf4j.core.impl.StandardSocketOption; + +/** + * Builder pattern.Configure XmemcachedClient's options,then build it + * + * @author dennis + * + */ +public class XMemcachedClientBuilder implements MemcachedClientBuilder { + + private static final Logger log = LoggerFactory.getLogger(XMemcachedClientBuilder.class); + + protected MemcachedSessionLocator sessionLocator = new ArrayMemcachedSessionLocator(); + protected BufferAllocator bufferAllocator = new SimpleBufferAllocator(); + protected Configuration configuration = getDefaultConfiguration(); + protected Map addressMap = + new LinkedHashMap(); + + protected int[] weights; + + protected long connectTimeout = MemcachedClient.DEFAULT_CONNECT_TIMEOUT; + + protected int connectionPoolSize = MemcachedClient.DEFAULT_CONNECTION_POOL_SIZE; + + @SuppressWarnings("unchecked") + protected final Map socketOptions = getDefaultSocketOptions(); + + protected List stateListeners = + new ArrayList(); + + protected Map authInfoMap = + new HashMap(); + + protected String name; + + protected boolean failureMode; + + protected boolean sanitizeKeys; + + protected KeyProvider keyProvider = DefaultKeyProvider.INSTANCE; + + protected int maxQueuedNoReplyOperations = MemcachedClient.DEFAULT_MAX_QUEUED_NOPS; + + protected long healSessionInterval = MemcachedClient.DEFAULT_HEAL_SESSION_INTERVAL; + + protected boolean enableHealSession = true; + + protected long opTimeout = MemcachedClient.DEFAULT_OP_TIMEOUT; + + public long getOpTimeout() { + return opTimeout; + } + + public void setOpTimeout(long opTimeout) { + if (opTimeout <= 0) + throw new IllegalArgumentException("Invalid opTimeout value:" + opTimeout); + this.opTimeout = opTimeout; + } + + public int getMaxQueuedNoReplyOperations() { + return maxQueuedNoReplyOperations; + } + + public long getHealSessionInterval() { + return healSessionInterval; + } + + public void setHealSessionInterval(long healSessionInterval) { + this.healSessionInterval = healSessionInterval; + } + + public boolean isEnableHealSession() { + return enableHealSession; + } + + public void setEnableHealSession(boolean enableHealSession) { + this.enableHealSession = enableHealSession; + } + + /** + * Set max queued noreply operations number + * + * @see MemcachedClient#DEFAULT_MAX_QUEUED_NOPS + * @param maxQueuedNoReplyOperations + * @since 1.3.8 + */ + public void setMaxQueuedNoReplyOperations(int maxQueuedNoReplyOperations) { + this.maxQueuedNoReplyOperations = maxQueuedNoReplyOperations; + } + + public void setSanitizeKeys(boolean sanitizeKeys) { + this.sanitizeKeys = sanitizeKeys; + } + + public void addStateListener(MemcachedClientStateListener stateListener) { + this.stateListeners.add(stateListener); + } + + @SuppressWarnings("unchecked") + public void setSocketOption(SocketOption socketOption, Object value) { + if (socketOption == null) { + throw new NullPointerException("Null socketOption"); + } + if (value == null) { + throw new NullPointerException("Null value"); + } + if (!socketOption.type().equals(value.getClass())) { + throw new IllegalArgumentException("Expected " + socketOption.type().getSimpleName() + + " value,but givend " + value.getClass().getSimpleName()); + } + this.socketOptions.put(socketOption, value); + } + + @SuppressWarnings("unchecked") + public Map getSocketOptions() { + return this.socketOptions; + } + + public final void setConnectionPoolSize(int poolSize) { + if (this.connectionPoolSize <= 0) { + throw new IllegalArgumentException("poolSize<=0"); + } + this.connectionPoolSize = poolSize; + } + + public void removeStateListener(MemcachedClientStateListener stateListener) { + this.stateListeners.remove(stateListener); + } + + public long getConnectTimeout() { + return connectTimeout; + } + + public void setConnectTimeout(long connectTimeout) { + this.connectTimeout = connectTimeout; + } + + public void setStateListeners(List stateListeners) { + if (stateListeners == null) { + throw new IllegalArgumentException("Null state listeners"); + } + this.stateListeners = stateListeners; + } + + protected CommandFactory commandFactory = new TextCommandFactory(); + + @SuppressWarnings("unchecked") + public static final Map getDefaultSocketOptions() { + Map map = new HashMap(); + map.put(StandardSocketOption.TCP_NODELAY, MemcachedClient.DEFAULT_TCP_NO_DELAY); + map.put(StandardSocketOption.SO_RCVBUF, MemcachedClient.DEFAULT_TCP_RECV_BUFF_SIZE); + map.put(StandardSocketOption.SO_KEEPALIVE, MemcachedClient.DEFAULT_TCP_KEEPLIVE); + map.put(StandardSocketOption.SO_SNDBUF, MemcachedClient.DEFAULT_TCP_SEND_BUFF_SIZE); + map.put(StandardSocketOption.SO_LINGER, 0); + map.put(StandardSocketOption.SO_REUSEADDR, true); + return map; + } + + public static final Configuration getDefaultConfiguration() { + final Configuration configuration = new Configuration(); + configuration.setSessionReadBufferSize(MemcachedClient.DEFAULT_SESSION_READ_BUFF_SIZE); + configuration.setReadThreadCount(MemcachedClient.DEFAULT_READ_THREAD_COUNT); + configuration.setSessionIdleTimeout(MemcachedClient.DEFAULT_SESSION_IDLE_TIMEOUT); + configuration.setWriteThreadCount(0); + return configuration; + } + + public boolean isFailureMode() { + return this.failureMode; + } + + public void setFailureMode(boolean failureMode) { + this.failureMode = failureMode; + } + + public final CommandFactory getCommandFactory() { + return this.commandFactory; + } + + public final void setCommandFactory(CommandFactory commandFactory) { + this.commandFactory = commandFactory; + } + + @SuppressWarnings({"rawtypes"}) + protected Transcoder transcoder = new SerializingTranscoder(); + + public XMemcachedClientBuilder(String addressList) { + this(AddrUtil.getAddresses(addressList)); + } + + public XMemcachedClientBuilder(List addressList) { + if (addressList != null) { + for (InetSocketAddress addr : addressList) { + this.addressMap.put(addr, null); + } + } + } + + public XMemcachedClientBuilder(List addressList, int[] weights) { + if (addressList != null) { + for (InetSocketAddress addr : addressList) { + this.addressMap.put(addr, null); + } + } + this.weights = weights; + } + + public XMemcachedClientBuilder(Map addressMap) { + this.addressMap = addressMap; + } + + public XMemcachedClientBuilder(Map addressMap, + int[] weights) { + this.addressMap = addressMap; + this.weights = weights; + } + + public XMemcachedClientBuilder() { + this((Map) null); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClientBuilder#getSessionLocator() + */ + public MemcachedSessionLocator getSessionLocator() { + return this.sessionLocator; + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClientBuilder#setSessionLocator(net. rubyeye + * .xmemcached.MemcachedSessionLocator) + */ + public void setSessionLocator(MemcachedSessionLocator sessionLocator) { + if (sessionLocator == null) { + throw new IllegalArgumentException("Null SessionLocator"); + } + this.sessionLocator = sessionLocator; + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClientBuilder#getBufferAllocator() + */ + public BufferAllocator getBufferAllocator() { + return this.bufferAllocator; + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClientBuilder#setBufferAllocator(net. + * rubyeye.xmemcached.buffer.BufferAllocator) + */ + public void setBufferAllocator(BufferAllocator bufferAllocator) { + if (bufferAllocator == null) { + throw new IllegalArgumentException("Null bufferAllocator"); + } + this.bufferAllocator = bufferAllocator; + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClientBuilder#getConfiguration() + */ + public Configuration getConfiguration() { + return this.configuration; + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClientBuilder#setConfiguration(com.google + * .code.yanf4j.config.Configuration) + */ + public void setConfiguration(Configuration configuration) { + this.configuration = configuration; + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClientBuilder#build() + */ + public MemcachedClient build() throws IOException { + XMemcachedClient memcachedClient; + // kestrel protocol use random session locator. + if (this.commandFactory.getProtocol() == Protocol.Kestrel) { + if (!(this.sessionLocator instanceof RandomMemcachedSessionLocaltor)) { + log.warn( + "Recommend to use `net.rubyeye.xmemcached.impl.RandomMemcachedSessionLocaltor` as session locator for kestrel protocol."); + } + } + if (this.weights == null) { + memcachedClient = new XMemcachedClient(this.sessionLocator, this.bufferAllocator, + this.configuration, this.socketOptions, this.commandFactory, this.transcoder, + this.addressMap, this.stateListeners, this.authInfoMap, this.connectionPoolSize, + this.connectTimeout, this.name, this.failureMode); + + } else { + if (this.addressMap == null) { + throw new IllegalArgumentException("Null Address map"); + } + if (this.addressMap.size() > this.weights.length) { + throw new IllegalArgumentException("Weights Array's length is less than server's number"); + } + memcachedClient = new XMemcachedClient(this.sessionLocator, this.bufferAllocator, + this.configuration, this.socketOptions, this.commandFactory, this.transcoder, + this.addressMap, this.weights, this.stateListeners, this.authInfoMap, + this.connectionPoolSize, this.connectTimeout, this.name, this.failureMode); + } + this.configureClient(memcachedClient); + return memcachedClient; + } + + protected void configureClient(XMemcachedClient memcachedClient) { + if (this.commandFactory.getProtocol() == Protocol.Kestrel) { + memcachedClient.setOptimizeGet(false); + } + memcachedClient.setConnectTimeout(connectTimeout); + memcachedClient.setSanitizeKeys(sanitizeKeys); + memcachedClient.setKeyProvider(this.keyProvider); + memcachedClient.setOpTimeout(this.opTimeout); + memcachedClient.setHealSessionInterval(this.healSessionInterval); + memcachedClient.setEnableHealSession(this.enableHealSession); + memcachedClient.setMaxQueuedNoReplyOperations(this.maxQueuedNoReplyOperations); + } + + @SuppressWarnings("rawtypes") + public Transcoder getTranscoder() { + return this.transcoder; + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClientBuilder#setTranscoder(transcoder) + */ + public void setTranscoder(Transcoder transcoder) { + if (transcoder == null) { + throw new IllegalArgumentException("Null Transcoder"); + } + this.transcoder = transcoder; + } + + public Map getAuthInfoMap() { + return this.authInfoMap; + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClientBuilder#setKeyProvider() + */ + public void setKeyProvider(KeyProvider keyProvider) { + if (keyProvider == null) + throw new IllegalArgumentException("null key provider"); + this.keyProvider = keyProvider; + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClientBuilder#addAuthInfo() + */ + public void addAuthInfo(InetSocketAddress address, AuthInfo authInfo) { + this.authInfoMap.put(address, authInfo); + } + + public void removeAuthInfo(InetSocketAddress address) { + this.authInfoMap.remove(address); + } + + public void setAuthInfoMap(Map authInfoMap) { + this.authInfoMap = authInfoMap; + } + + public String getName() { + return this.name; + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.MemcachedClientBuilder#setName() + */ + public void setName(String name) { + this.name = name; + + } + + public void setSelectorPoolSize(int selectorPoolSize) { + getConfiguration().setSelectorPoolSize(selectorPoolSize); + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/XMemcachedClientMBean.java b/src/main/java/net/rubyeye/xmemcached/XMemcachedClientMBean.java index 21b9573cf..602d37e14 100644 --- a/src/main/java/net/rubyeye/xmemcached/XMemcachedClientMBean.java +++ b/src/main/java/net/rubyeye/xmemcached/XMemcachedClientMBean.java @@ -11,56 +11,51 @@ */ public interface XMemcachedClientMBean { - /** - * Add memcached servers - * - * @param host - * a String in the form of "[host1]:[port1],[host2]:[port2] - * [host3]:[port3],[host4]:[port4]" - */ - public void addServer(String hostList) throws IOException; - - /** - * Add a memcached server - * - * @param server - * a String in the form of "[host1]:[port1],[host2]:[port2]" - * @param weight - * server's weight - */ - public void addOneServerWithWeight(String server, int weight) - throws IOException; - - /** - * Remove memcached servers - * - * @param host - * a string in the form of "[host1]:[port1],[host2]:[port2] - * [host3]:[port3],[host4]:[port4]" - */ - public void removeServer(String hostList); - - /** - * Get all connected memcached servers - * - * @return a list of string,every string is in the form of - * "[host1]:[port1](weight=num1) [host2]:[port2](weight=num1)" - */ - public List getServersDescription(); - - /** - * Set a memcached server's weight - * - * @param server - * @param weight - */ - public void setServerWeight(String server, int weight); - - /** - * Return the cache instance name - * - * @return - */ - public String getName(); - -} \ No newline at end of file + /** + * Add memcached servers + * + * @param host a String in the form of "[host1]:[port1],[host2]:[port2] + * [host3]:[port3],[host4]:[port4]" + */ + public void addServer(String hostList) throws IOException; + + /** + * Add a memcached server + * + * @param server a String in the form of "[host1]:[port1],[host2]:[port2]" + * @param weight server's weight + */ + public void addOneServerWithWeight(String server, int weight) throws IOException; + + /** + * Remove memcached servers + * + * @param host a string in the form of "[host1]:[port1],[host2]:[port2] + * [host3]:[port3],[host4]:[port4]" + */ + public void removeServer(String hostList); + + /** + * Get all connected memcached servers + * + * @return a list of string,every string is in the form of "[host1]:[port1](weight=num1) + * [host2]:[port2](weight=num1)" + */ + public List getServersDescription(); + + /** + * Set a memcached server's weight + * + * @param server + * @param weight + */ + public void setServerWeight(String server, int weight); + + /** + * Return the cache instance name + * + * @return + */ + public String getName(); + +} diff --git a/src/main/java/net/rubyeye/xmemcached/auth/AuthInfo.java b/src/main/java/net/rubyeye/xmemcached/auth/AuthInfo.java index c2e7d7999..512e37dd0 100644 --- a/src/main/java/net/rubyeye/xmemcached/auth/AuthInfo.java +++ b/src/main/java/net/rubyeye/xmemcached/auth/AuthInfo.java @@ -1,96 +1,85 @@ -package net.rubyeye.xmemcached.auth; - -import javax.security.auth.callback.CallbackHandler; - -/** - * Authentication infomation for a memcached server - * - * @author dennis - * - */ -public class AuthInfo { - private final CallbackHandler callbackHandler; - private final String[] mechanisms; - private final int maxAttempts = Integer.parseInt(System - .getProperty("net.rubyeye.xmemcached.auth_max_attempts", "-1")); - private int attempts; - - public synchronized boolean isValid() { - return this.attempts <= this.maxAttempts || this.maxAttempts < 0; - } - - public synchronized boolean isFirstTime() { - return this.attempts == 0; - } - - public synchronized void increaseAttempts() { - this.attempts++; - } - - public AuthInfo(CallbackHandler callbackHandler, String[] mechanisms) { - super(); - this.callbackHandler = callbackHandler; - this.mechanisms = mechanisms; - } - - public int getMaxAttempts() { - return maxAttempts; - } - - /** - * Get a typical auth descriptor for PLAIN auth with the given username and - * password. - * - * @param u - * the username - * @param p - * the password - * - * @return an AuthInfo - */ - public static AuthInfo plain(String username, String password) { - return new AuthInfo(new PlainCallbackHandler(username, password), - new String[]{"PLAIN"}); - } - - /** - * Get a typical auth descriptor for CRAM-MD5 auth with the given username - * and password. - * - * @param u - * the username - * @param p - * the password - * - * @return an AuthInfo - */ - public static AuthInfo cramMD5(String username, String password) { - return new AuthInfo(new PlainCallbackHandler(username, password), - new String[]{"CRAM-MD5"}); - } - - /** - * Get a typical auth descriptor for CRAM-MD5 or PLAIN auth with the given - * username and password. - * - * @param u - * the username - * @param p - * the password - * - * @return an AuthInfo - */ - public static AuthInfo typical(String username, String password) { - return new AuthInfo(new PlainCallbackHandler(username, password), - new String[]{"CRAM-MD5", "PLAIN"}); - } - - public CallbackHandler getCallbackHandler() { - return callbackHandler; - } - - public String[] getMechanisms() { - return mechanisms; - } - -} +package net.rubyeye.xmemcached.auth; + +import javax.security.auth.callback.CallbackHandler; + +/** + * Authentication infomation for a memcached server + * + * @author dennis + * + */ +public class AuthInfo { + private final CallbackHandler callbackHandler; + private final String[] mechanisms; + private final int maxAttempts = + Integer.parseInt(System.getProperty("net.rubyeye.xmemcached.auth_max_attempts", "-1")); + private int attempts; + + public synchronized boolean isValid() { + return this.attempts <= this.maxAttempts || this.maxAttempts < 0; + } + + public synchronized boolean isFirstTime() { + return this.attempts == 0; + } + + public synchronized void increaseAttempts() { + this.attempts++; + } + + public AuthInfo(CallbackHandler callbackHandler, String[] mechanisms) { + super(); + this.callbackHandler = callbackHandler; + this.mechanisms = mechanisms; + } + + public int getMaxAttempts() { + return maxAttempts; + } + + /** + * Get a typical auth descriptor for PLAIN auth with the given username and password. + * + * @param u the username + * @param p the password + * + * @return an AuthInfo + */ + public static AuthInfo plain(String username, String password) { + return new AuthInfo(new PlainCallbackHandler(username, password), new String[] {"PLAIN"}); + } + + /** + * Get a typical auth descriptor for CRAM-MD5 auth with the given username and password. + * + * @param u the username + * @param p the password + * + * @return an AuthInfo + */ + public static AuthInfo cramMD5(String username, String password) { + return new AuthInfo(new PlainCallbackHandler(username, password), new String[] {"CRAM-MD5"}); + } + + /** + * Get a typical auth descriptor for CRAM-MD5 or PLAIN auth with the given username and password. + * + * @param u the username + * @param p the password + * + * @return an AuthInfo + */ + public static AuthInfo typical(String username, String password) { + return new AuthInfo(new PlainCallbackHandler(username, password), + new String[] {"CRAM-MD5", "PLAIN"}); + } + + public CallbackHandler getCallbackHandler() { + return callbackHandler; + } + + public String[] getMechanisms() { + return mechanisms; + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/auth/AuthMemcachedConnectListener.java b/src/main/java/net/rubyeye/xmemcached/auth/AuthMemcachedConnectListener.java index 7e93061c3..e1f60e26d 100644 --- a/src/main/java/net/rubyeye/xmemcached/auth/AuthMemcachedConnectListener.java +++ b/src/main/java/net/rubyeye/xmemcached/auth/AuthMemcachedConnectListener.java @@ -1,45 +1,40 @@ -package net.rubyeye.xmemcached.auth; - -import java.net.InetSocketAddress; -import java.util.Map; - -import net.rubyeye.xmemcached.MemcachedClient; -import net.rubyeye.xmemcached.XMemcachedClient; -import net.rubyeye.xmemcached.impl.MemcachedTCPSession; -import net.rubyeye.xmemcached.networking.MemcachedSession; -import net.rubyeye.xmemcached.networking.MemcachedSessionConnectListener; - -/** - * Client state listener for auth - * - * @author dennis - * - */ -public class AuthMemcachedConnectListener - implements - MemcachedSessionConnectListener { - - public void onConnect(MemcachedSession session, MemcachedClient client) { - MemcachedTCPSession tcpSession = (MemcachedTCPSession) session; - Map authInfoMap = client.getAuthInfoMap(); - if (authInfoMap != null) { - AuthInfo authInfo = authInfoMap - .get(tcpSession.getRemoteSocketAddress()); - if (authInfo != null) { - XMemcachedClient xMemcachedClient = (XMemcachedClient) client; - AuthTask task = new AuthTask(authInfo, - xMemcachedClient.getCommandFactory(), tcpSession); - task.start(); - // First time,try to wait - if (authInfo.isFirstTime()) { - try { - task.join(1000); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - } - } - } - -} +package net.rubyeye.xmemcached.auth; + +import java.net.InetSocketAddress; +import java.util.Map; +import net.rubyeye.xmemcached.MemcachedClient; +import net.rubyeye.xmemcached.XMemcachedClient; +import net.rubyeye.xmemcached.impl.MemcachedTCPSession; +import net.rubyeye.xmemcached.networking.MemcachedSession; +import net.rubyeye.xmemcached.networking.MemcachedSessionConnectListener; + +/** + * Client state listener for auth + * + * @author dennis + * + */ +public class AuthMemcachedConnectListener implements MemcachedSessionConnectListener { + + public void onConnect(MemcachedSession session, MemcachedClient client) { + MemcachedTCPSession tcpSession = (MemcachedTCPSession) session; + Map authInfoMap = client.getAuthInfoMap(); + if (authInfoMap != null) { + AuthInfo authInfo = authInfoMap.get(tcpSession.getRemoteSocketAddress()); + if (authInfo != null) { + XMemcachedClient xMemcachedClient = (XMemcachedClient) client; + AuthTask task = new AuthTask(authInfo, xMemcachedClient.getCommandFactory(), tcpSession); + task.start(); + // First time,try to wait + if (authInfo.isFirstTime()) { + try { + task.join(1000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + } + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/auth/AuthTask.java b/src/main/java/net/rubyeye/xmemcached/auth/AuthTask.java index 66af0e417..efbea4383 100644 --- a/src/main/java/net/rubyeye/xmemcached/auth/AuthTask.java +++ b/src/main/java/net/rubyeye/xmemcached/auth/AuthTask.java @@ -1,168 +1,149 @@ -package net.rubyeye.xmemcached.auth; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.security.sasl.Sasl; -import javax.security.sasl.SaslClient; -import javax.security.sasl.SaslException; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import net.rubyeye.xmemcached.CommandFactory; - -import net.rubyeye.xmemcached.command.Command; -import net.rubyeye.xmemcached.command.binary.BaseBinaryCommand; -import net.rubyeye.xmemcached.command.binary.ResponseStatus; -import net.rubyeye.xmemcached.impl.MemcachedTCPSession; -import net.rubyeye.xmemcached.utils.ByteUtils; - -import net.rubyeye.xmemcached.MemcachedClient; - -/** - * Authentication task - * - * @author dennis - * - */ -public class AuthTask extends Thread { - private final AuthInfo authInfo; - private final CommandFactory commandFactory; - private MemcachedTCPSession memcachedTCPSession; - public static final byte[] EMPTY_BYTES = new byte[0]; - static final Logger log = LoggerFactory.getLogger(AuthTask.class); - private SaslClient saslClient; - - public AuthTask(AuthInfo authInfo, CommandFactory commandFactory, - MemcachedTCPSession memcachedTCPSession) { - super(); - this.authInfo = authInfo; - this.commandFactory = commandFactory; - this.memcachedTCPSession = memcachedTCPSession; - } - - public void run() { - if (this.authInfo.isValid()) { - doAuth(); - this.authInfo.increaseAttempts(); - } - } - - private void doAuth() { - try { - final AtomicBoolean done = new AtomicBoolean(false); - Command command = startAuth(); - - while (!done.get()) { - // wait previous command response - waitCommand(command, done); - // process response - ResponseStatus responseStatus = ((BaseBinaryCommand) command) - .getResponseStatus(); - switch (responseStatus) { - case NO_ERROR : - done.set(true); - log.info("Authentication to " - + this.memcachedTCPSession - .getRemoteSocketAddress() - + " successfully"); - break; - case AUTH_REQUIRED : - log.error("Authentication failed to " - + this.memcachedTCPSession - .getRemoteSocketAddress()); - log.warn("Reopen connection to " - + this.memcachedTCPSession - .getRemoteSocketAddress() - + ",beacause auth fail"); - this.memcachedTCPSession.setAuthFailed(true); - - // It it is not first time ,try to sleep 1 second - if (!this.authInfo.isFirstTime()) { - Thread.sleep(1000); - } - this.memcachedTCPSession.close(); - done.set(true); - break; - case FUTHER_AUTH_REQUIRED : - String result = String.valueOf(command.getResult()); - byte[] response = saslClient - .evaluateChallenge(ByteUtils.getBytes(result)); - CountDownLatch latch = new CountDownLatch(1); - command = commandFactory.createAuthStepCommand( - saslClient.getMechanismName(), latch, response); - if (!this.memcachedTCPSession.isClosed()) - this.memcachedTCPSession.write(command); - else { - log.error( - "Authentication fail,because the connection has been closed"); - throw new RuntimeException( - "Authentication fai,connection has been close"); - } - - break; - default : - log.error("Authentication failed to " - + this.memcachedTCPSession - .getRemoteSocketAddress() - + ",response status=" + responseStatus); - command = startAuth(); - break; - - } - - } - } catch (Exception e) { - log.error("Create saslClient error", e); - } finally { - destroySaslClient(); - } - } - - private void destroySaslClient() { - if (saslClient != null) { - try { - saslClient.dispose(); - } catch (SaslException e) { - log.error("Dispose saslClient error", e); - } - this.saslClient = null; - } - } - - private Command startAuth() throws SaslException { - // destroy previous client. - destroySaslClient(); - - this.saslClient = Sasl.createSaslClient(authInfo.getMechanisms(), null, - "memcached", - memcachedTCPSession.getRemoteSocketAddress().toString(), null, - this.authInfo.getCallbackHandler()); - byte[] response = saslClient.hasInitialResponse() - ? saslClient.evaluateChallenge(EMPTY_BYTES) - : EMPTY_BYTES; - CountDownLatch latch = new CountDownLatch(1); - Command command = this.commandFactory.createAuthStartCommand( - saslClient.getMechanismName(), latch, response); - if (!this.memcachedTCPSession.isClosed()) - this.memcachedTCPSession.write(command); - else { - log.error( - "Authentication fail,because the connection has been closed"); - throw new RuntimeException( - "Authentication fai,connection has been close"); - } - return command; - } - - private void waitCommand(Command cmd, AtomicBoolean done) { - try { - cmd.getLatch().await(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - done.set(true); - } - } - -} +package net.rubyeye.xmemcached.auth; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import net.rubyeye.xmemcached.CommandFactory; +import net.rubyeye.xmemcached.command.Command; +import net.rubyeye.xmemcached.command.binary.BaseBinaryCommand; +import net.rubyeye.xmemcached.command.binary.ResponseStatus; +import net.rubyeye.xmemcached.impl.MemcachedTCPSession; +import net.rubyeye.xmemcached.utils.ByteUtils; +import net.rubyeye.xmemcached.MemcachedClient; + +/** + * Authentication task + * + * @author dennis + * + */ +public class AuthTask extends Thread { + private final AuthInfo authInfo; + private final CommandFactory commandFactory; + private MemcachedTCPSession memcachedTCPSession; + public static final byte[] EMPTY_BYTES = new byte[0]; + static final Logger log = LoggerFactory.getLogger(AuthTask.class); + private SaslClient saslClient; + + public AuthTask(AuthInfo authInfo, CommandFactory commandFactory, + MemcachedTCPSession memcachedTCPSession) { + super(); + this.authInfo = authInfo; + this.commandFactory = commandFactory; + this.memcachedTCPSession = memcachedTCPSession; + } + + public void run() { + if (this.authInfo.isValid()) { + doAuth(); + this.authInfo.increaseAttempts(); + } + } + + private void doAuth() { + try { + final AtomicBoolean done = new AtomicBoolean(false); + Command command = startAuth(); + + while (!done.get()) { + // wait previous command response + waitCommand(command, done); + // process response + ResponseStatus responseStatus = ((BaseBinaryCommand) command).getResponseStatus(); + switch (responseStatus) { + case NO_ERROR: + done.set(true); + log.info("Authentication to " + this.memcachedTCPSession.getRemoteSocketAddress() + + " successfully"); + break; + case AUTH_REQUIRED: + log.error( + "Authentication failed to " + this.memcachedTCPSession.getRemoteSocketAddress()); + log.warn("Reopen connection to " + this.memcachedTCPSession.getRemoteSocketAddress() + + ",beacause auth fail"); + this.memcachedTCPSession.setAuthFailed(true); + + // It it is not first time ,try to sleep 1 second + if (!this.authInfo.isFirstTime()) { + Thread.sleep(1000); + } + this.memcachedTCPSession.close(); + done.set(true); + break; + case FUTHER_AUTH_REQUIRED: + String result = String.valueOf(command.getResult()); + byte[] response = saslClient.evaluateChallenge(ByteUtils.getBytes(result)); + CountDownLatch latch = new CountDownLatch(1); + command = commandFactory.createAuthStepCommand(saslClient.getMechanismName(), latch, + response); + if (!this.memcachedTCPSession.isClosed()) + this.memcachedTCPSession.write(command); + else { + log.error("Authentication fail,because the connection has been closed"); + throw new RuntimeException("Authentication fai,connection has been close"); + } + + break; + default: + log.error( + "Authentication failed to " + this.memcachedTCPSession.getRemoteSocketAddress() + + ",response status=" + responseStatus); + command = startAuth(); + break; + + } + + } + } catch (Exception e) { + log.error("Create saslClient error", e); + } finally { + destroySaslClient(); + } + } + + private void destroySaslClient() { + if (saslClient != null) { + try { + saslClient.dispose(); + } catch (SaslException e) { + log.error("Dispose saslClient error", e); + } + this.saslClient = null; + } + } + + private Command startAuth() throws SaslException { + // destroy previous client. + destroySaslClient(); + + this.saslClient = Sasl.createSaslClient(authInfo.getMechanisms(), null, "memcached", + memcachedTCPSession.getRemoteSocketAddress().toString(), null, + this.authInfo.getCallbackHandler()); + byte[] response = + saslClient.hasInitialResponse() ? saslClient.evaluateChallenge(EMPTY_BYTES) : EMPTY_BYTES; + CountDownLatch latch = new CountDownLatch(1); + Command command = + this.commandFactory.createAuthStartCommand(saslClient.getMechanismName(), latch, response); + if (!this.memcachedTCPSession.isClosed()) + this.memcachedTCPSession.write(command); + else { + log.error("Authentication fail,because the connection has been closed"); + throw new RuntimeException("Authentication fai,connection has been close"); + } + return command; + } + + private void waitCommand(Command cmd, AtomicBoolean done) { + try { + cmd.getLatch().await(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + done.set(true); + } + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/auth/PlainCallbackHandler.java b/src/main/java/net/rubyeye/xmemcached/auth/PlainCallbackHandler.java index 851161abb..0199f876e 100644 --- a/src/main/java/net/rubyeye/xmemcached/auth/PlainCallbackHandler.java +++ b/src/main/java/net/rubyeye/xmemcached/auth/PlainCallbackHandler.java @@ -1,41 +1,38 @@ -package net.rubyeye.xmemcached.auth; - -import java.io.IOException; - -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.UnsupportedCallbackException; - -/** - * A callback handler for name/password authentication - * - * @author dennis - * - */ -public class PlainCallbackHandler implements CallbackHandler { - private String username; - private String password; - - public PlainCallbackHandler(String username, String password) { - super(); - this.username = username; - this.password = password; - } - - public void handle(Callback[] callbacks) - throws IOException, UnsupportedCallbackException { - for (Callback callback : callbacks) { - if (callback instanceof NameCallback) { - ((NameCallback) callback).setName(this.username); - } else if (callback instanceof PasswordCallback) { - ((PasswordCallback) callback) - .setPassword(password.toCharArray()); - } else - throw new UnsupportedCallbackException(callback); - } - - } - -} +package net.rubyeye.xmemcached.auth; + +import java.io.IOException; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; + +/** + * A callback handler for name/password authentication + * + * @author dennis + * + */ +public class PlainCallbackHandler implements CallbackHandler { + private String username; + private String password; + + public PlainCallbackHandler(String username, String password) { + super(); + this.username = username; + this.password = password; + } + + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { + for (Callback callback : callbacks) { + if (callback instanceof NameCallback) { + ((NameCallback) callback).setName(this.username); + } else if (callback instanceof PasswordCallback) { + ((PasswordCallback) callback).setPassword(password.toCharArray()); + } else + throw new UnsupportedCallbackException(callback); + } + + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/auth/package.html b/src/main/java/net/rubyeye/xmemcached/auth/package.html index 6e2ccc48e..23da2f6b8 100644 --- a/src/main/java/net/rubyeye/xmemcached/auth/package.html +++ b/src/main/java/net/rubyeye/xmemcached/auth/package.html @@ -1,14 +1,10 @@ - - + - -SASL supporting for memcached 1.4.3 or later - - - -

Memcached 1.4.3 or later version has supported SASL authentication,these classes are used for that

- - - + + SASL supporting for memcached 1.4.3 or later + + +

Memcached 1.4.3 or later version has supported SASL authentication,these classes are used for that

+ + \ No newline at end of file diff --git a/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java b/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java index eb01cf2af..2c56113dc 100644 --- a/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java +++ b/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClient.java @@ -1,317 +1,287 @@ -package net.rubyeye.xmemcached.aws; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeoutException; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.code.yanf4j.config.Configuration; -import com.google.code.yanf4j.core.Session; -import com.google.code.yanf4j.core.SocketOption; - -import net.rubyeye.xmemcached.CommandFactory; -import net.rubyeye.xmemcached.MemcachedClientStateListener; -import net.rubyeye.xmemcached.MemcachedSessionLocator; -import net.rubyeye.xmemcached.XMemcachedClient; -import net.rubyeye.xmemcached.XMemcachedClientBuilder; -import net.rubyeye.xmemcached.auth.AuthInfo; -import net.rubyeye.xmemcached.buffer.BufferAllocator; -import net.rubyeye.xmemcached.buffer.SimpleBufferAllocator; -import net.rubyeye.xmemcached.command.Command; -import net.rubyeye.xmemcached.command.TextCommandFactory; -import net.rubyeye.xmemcached.exception.MemcachedException; -import net.rubyeye.xmemcached.impl.ArrayMemcachedSessionLocator; -import net.rubyeye.xmemcached.transcoders.SerializingTranscoder; -import net.rubyeye.xmemcached.transcoders.Transcoder; -import net.rubyeye.xmemcached.utils.InetSocketAddressWrapper; - -/** - * AWS ElasticCache Client. - * - * @since 2.3.0 - * @author dennis - * - */ -public class AWSElasticCacheClient extends XMemcachedClient - implements - ConfigUpdateListener { - - private static final Logger log = LoggerFactory - .getLogger(AWSElasticCacheClient.class); - - private boolean firstTimeUpdate = true; - - private List configAddrs = new ArrayList(); - - public synchronized void onUpdate(ClusterConfigration config) { - - if (firstTimeUpdate) { - firstTimeUpdate = false; - removeConfigAddrs(); - } - - List oldList = this.currentClusterConfiguration != null - ? this.currentClusterConfiguration.getNodeList() - : Collections.EMPTY_LIST; - List newList = config.getNodeList(); - - List addNodes = new ArrayList(); - List removeNodes = new ArrayList(); - - for (CacheNode node : newList) { - if (!oldList.contains(node)) { - addNodes.add(node); - } - } - - for (CacheNode node : oldList) { - if (!newList.contains(node)) { - removeNodes.add(node); - } - } - - // Begin to update server list - for (CacheNode node : addNodes) { - try { - this.connect(new InetSocketAddressWrapper( - node.getInetSocketAddress(), - this.configPoller.getCacheNodeOrder(node), 1, null)); - } catch (IOException e) { - log.error("Connect to " + node + "failed.", e); - } - } - - for (CacheNode node : removeNodes) { - try { - this.removeAddr(node.getInetSocketAddress()); - } catch (Exception e) { - log.error("Remove " + node + " failed."); - } - } - - this.currentClusterConfiguration = config; - } - - private void removeConfigAddrs() { - for (InetSocketAddress configAddr : this.configAddrs) { - this.removeAddr(configAddr); - while (this.getConnector().getSessionByAddress(configAddr) != null - && this.getConnector().getSessionByAddress(configAddr) - .size() > 0) { - try { - Thread.sleep(10); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - } - } - - private final ConfigurationPoller configPoller; - - /** - * Default elasticcache configuration poll interval, it's one minute. - */ - public static final long DEFAULT_POLL_CONFIG_INTERVAL_MS = 60000; - - /** - * Construct an AWSElasticCacheClient instance with one config address and - * default poll interval. - * - * @since 2.3.0 - * @param addr - * config server address. - * @throws IOException - */ - public AWSElasticCacheClient(InetSocketAddress addr) throws IOException { - this(addr, DEFAULT_POLL_CONFIG_INTERVAL_MS); - } - - /** - * Construct an AWSElasticCacheClient instance with one config address and - * poll interval. - * - * @since 2.3.0 - * @param addr - * config server address. - * @param pollConfigIntervalMills - * config poll interval in milliseconds. - * @throws IOException - */ - public AWSElasticCacheClient(InetSocketAddress addr, - long pollConfigIntervalMills) throws IOException { - this(addr, pollConfigIntervalMills, new TextCommandFactory()); - } - - public AWSElasticCacheClient(InetSocketAddress addr, - long pollConfigIntervalMills, CommandFactory cmdFactory) - throws IOException { - this(asList(addr), pollConfigIntervalMills, cmdFactory); - } - - private static List asList(InetSocketAddress addr) { - List addrs = new ArrayList(); - addrs.add(addr); - return addrs; - } - - /** - * Construct an AWSElasticCacheClient instance with config server addresses - * and default config poll interval. - * - * @since 2.3.0 - * @param addrs - * config server list. - * @throws IOException - */ - public AWSElasticCacheClient(List addrs) - throws IOException { - this(addrs, DEFAULT_POLL_CONFIG_INTERVAL_MS); - } - - /** - * Construct an AWSElasticCacheClient instance with config server addresses. - * - * @since 2.3.0 - * @param addrs - * @param pollConfigIntervalMills - * @throws IOException - */ - public AWSElasticCacheClient(List addrs, - long pollConfigIntervalMills) throws IOException { - this(addrs, pollConfigIntervalMills, new TextCommandFactory()); - } - - /** - * Construct an AWSElasticCacheClient instance with config server addresses. - * - * @since 2.3.0 - * @param addrs - * config server list. - * @param pollConfigIntervalMills - * config poll interval in milliseconds. - * @param commandFactory - * protocol command factory. - * @throws IOException - */ - @SuppressWarnings("unchecked") - public AWSElasticCacheClient(List addrs, - long pollConfigIntervalMills, CommandFactory commandFactory) - throws IOException { - this(new ArrayMemcachedSessionLocator(), new SimpleBufferAllocator(), - XMemcachedClientBuilder.getDefaultConfiguration(), - XMemcachedClientBuilder.getDefaultSocketOptions(), - new TextCommandFactory(), new SerializingTranscoder(), - (List) Collections.EMPTY_LIST, - (Map) Collections.EMPTY_MAP, 1, - XMemcachedClient.DEFAULT_CONNECT_TIMEOUT, null, true, addrs, - pollConfigIntervalMills); - - } - - private static Map getAddressMapFromConfigAddrs( - List configAddrs) { - Map m = new HashMap(); - for (InetSocketAddress addr : configAddrs) { - m.put(addr, null); - } - return m; - } - - AWSElasticCacheClient(MemcachedSessionLocator locator, - BufferAllocator allocator, Configuration conf, - Map socketOptions, - CommandFactory commandFactory, Transcoder transcoder, - List stateListeners, - Map map, int poolSize, - long connectTimeout, String name, boolean failureMode, - List configAddrs, long pollConfigIntervalMills) - throws IOException { - super(locator, allocator, conf, socketOptions, commandFactory, - transcoder, getAddressMapFromConfigAddrs(configAddrs), - stateListeners, map, poolSize, connectTimeout, name, - failureMode); - if (pollConfigIntervalMills <= 0) { - throw new IllegalArgumentException( - "Invalid pollConfigIntervalMills value."); - } - // Use failure mode by default. - this.commandFactory = commandFactory; - this.setFailureMode(true); - this.configAddrs = configAddrs; - this.configPoller = new ConfigurationPoller(this, - pollConfigIntervalMills); - // Run at once to get config at startup. - // It will call onUpdate in the same thread. - this.configPoller.run(); - if (this.currentClusterConfiguration == null) { - throw new IllegalStateException( - "Retrieve ElasticCache config from `" - + configAddrs.toString() + "` failed."); - } - this.configPoller.start(); - } - - private volatile ClusterConfigration currentClusterConfiguration; - - /** - * Get cluster config from cache node by network command. - * - * @return - */ - public ClusterConfigration getConfig() - throws MemcachedException, InterruptedException, TimeoutException { - return this.getConfig("cluster"); - } - - /** - * Get config by key from cache node by network command. - * - * @since 2.3.0 - * @return clusetr config. - */ - public ClusterConfigration getConfig(String key) - throws MemcachedException, InterruptedException, TimeoutException { - Command cmd = this.commandFactory - .createAWSElasticCacheConfigCommand("get", key); - final Session session = this.sendCommand(cmd); - this.latchWait(cmd, opTimeout, session); - cmd.getIoBuffer().free(); - this.checkException(cmd); - String result = (String) cmd.getResult(); - if (result == null) { - throw new MemcachedException( - "Operation fail,may be caused by networking or timeout"); - } - return AWSUtils.parseConfiguration(result); - } - - @Override - protected void shutdown0() { - super.shutdown0(); - if (this.configPoller != null) { - try { - this.configPoller.stop(); - } catch (Exception e) { - // ignore - } - } - } - - /** - * Get the current using configuration in memory. - * - * @since 2.3.0 - * @return current cluster config. - */ - public ClusterConfigration getCurrentConfig() { - return this.currentClusterConfiguration; - } -} +package net.rubyeye.xmemcached.aws; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeoutException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.google.code.yanf4j.config.Configuration; +import com.google.code.yanf4j.core.Session; +import com.google.code.yanf4j.core.SocketOption; +import net.rubyeye.xmemcached.CommandFactory; +import net.rubyeye.xmemcached.MemcachedClientStateListener; +import net.rubyeye.xmemcached.MemcachedSessionLocator; +import net.rubyeye.xmemcached.XMemcachedClient; +import net.rubyeye.xmemcached.XMemcachedClientBuilder; +import net.rubyeye.xmemcached.auth.AuthInfo; +import net.rubyeye.xmemcached.buffer.BufferAllocator; +import net.rubyeye.xmemcached.buffer.SimpleBufferAllocator; +import net.rubyeye.xmemcached.command.Command; +import net.rubyeye.xmemcached.command.TextCommandFactory; +import net.rubyeye.xmemcached.exception.MemcachedException; +import net.rubyeye.xmemcached.impl.ArrayMemcachedSessionLocator; +import net.rubyeye.xmemcached.transcoders.SerializingTranscoder; +import net.rubyeye.xmemcached.transcoders.Transcoder; +import net.rubyeye.xmemcached.utils.InetSocketAddressWrapper; + +/** + * AWS ElasticCache Client. + * + * @since 2.3.0 + * @author dennis + * + */ +public class AWSElasticCacheClient extends XMemcachedClient implements ConfigUpdateListener { + + private static final Logger log = LoggerFactory.getLogger(AWSElasticCacheClient.class); + + private boolean firstTimeUpdate = true; + + private List configAddrs = new ArrayList(); + + public synchronized void onUpdate(ClusterConfigration config) { + + if (firstTimeUpdate) { + firstTimeUpdate = false; + removeConfigAddrs(); + } + + List oldList = + this.currentClusterConfiguration != null ? this.currentClusterConfiguration.getNodeList() + : Collections.EMPTY_LIST; + List newList = config.getNodeList(); + + List addNodes = new ArrayList(); + List removeNodes = new ArrayList(); + + for (CacheNode node : newList) { + if (!oldList.contains(node)) { + addNodes.add(node); + } + } + + for (CacheNode node : oldList) { + if (!newList.contains(node)) { + removeNodes.add(node); + } + } + + // Begin to update server list + for (CacheNode node : addNodes) { + try { + this.connect(new InetSocketAddressWrapper(node.getInetSocketAddress(), + this.configPoller.getCacheNodeOrder(node), 1, null)); + } catch (IOException e) { + log.error("Connect to " + node + "failed.", e); + } + } + + for (CacheNode node : removeNodes) { + try { + this.removeAddr(node.getInetSocketAddress()); + } catch (Exception e) { + log.error("Remove " + node + " failed."); + } + } + + this.currentClusterConfiguration = config; + } + + private void removeConfigAddrs() { + for (InetSocketAddress configAddr : this.configAddrs) { + this.removeAddr(configAddr); + while (this.getConnector().getSessionByAddress(configAddr) != null + && this.getConnector().getSessionByAddress(configAddr).size() > 0) { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + } + + private final ConfigurationPoller configPoller; + + /** + * Default elasticcache configuration poll interval, it's one minute. + */ + public static final long DEFAULT_POLL_CONFIG_INTERVAL_MS = 60000; + + /** + * Construct an AWSElasticCacheClient instance with one config address and default poll interval. + * + * @since 2.3.0 + * @param addr config server address. + * @throws IOException + */ + public AWSElasticCacheClient(InetSocketAddress addr) throws IOException { + this(addr, DEFAULT_POLL_CONFIG_INTERVAL_MS); + } + + /** + * Construct an AWSElasticCacheClient instance with one config address and poll interval. + * + * @since 2.3.0 + * @param addr config server address. + * @param pollConfigIntervalMills config poll interval in milliseconds. + * @throws IOException + */ + public AWSElasticCacheClient(InetSocketAddress addr, long pollConfigIntervalMills) + throws IOException { + this(addr, pollConfigIntervalMills, new TextCommandFactory()); + } + + public AWSElasticCacheClient(InetSocketAddress addr, long pollConfigIntervalMills, + CommandFactory cmdFactory) throws IOException { + this(asList(addr), pollConfigIntervalMills, cmdFactory); + } + + private static List asList(InetSocketAddress addr) { + List addrs = new ArrayList(); + addrs.add(addr); + return addrs; + } + + /** + * Construct an AWSElasticCacheClient instance with config server addresses and default config + * poll interval. + * + * @since 2.3.0 + * @param addrs config server list. + * @throws IOException + */ + public AWSElasticCacheClient(List addrs) throws IOException { + this(addrs, DEFAULT_POLL_CONFIG_INTERVAL_MS); + } + + /** + * Construct an AWSElasticCacheClient instance with config server addresses. + * + * @since 2.3.0 + * @param addrs + * @param pollConfigIntervalMills + * @throws IOException + */ + public AWSElasticCacheClient(List addrs, long pollConfigIntervalMills) + throws IOException { + this(addrs, pollConfigIntervalMills, new TextCommandFactory()); + } + + /** + * Construct an AWSElasticCacheClient instance with config server addresses. + * + * @since 2.3.0 + * @param addrs config server list. + * @param pollConfigIntervalMills config poll interval in milliseconds. + * @param commandFactory protocol command factory. + * @throws IOException + */ + @SuppressWarnings("unchecked") + public AWSElasticCacheClient(List addrs, long pollConfigIntervalMills, + CommandFactory commandFactory) throws IOException { + this(new ArrayMemcachedSessionLocator(), new SimpleBufferAllocator(), + XMemcachedClientBuilder.getDefaultConfiguration(), + XMemcachedClientBuilder.getDefaultSocketOptions(), new TextCommandFactory(), + new SerializingTranscoder(), (List) Collections.EMPTY_LIST, + (Map) Collections.EMPTY_MAP, 1, + XMemcachedClient.DEFAULT_CONNECT_TIMEOUT, null, true, addrs, pollConfigIntervalMills); + + } + + private static Map getAddressMapFromConfigAddrs( + List configAddrs) { + Map m = + new HashMap(); + for (InetSocketAddress addr : configAddrs) { + m.put(addr, null); + } + return m; + } + + AWSElasticCacheClient(MemcachedSessionLocator locator, BufferAllocator allocator, + Configuration conf, Map socketOptions, CommandFactory commandFactory, + Transcoder transcoder, List stateListeners, + Map map, int poolSize, long connectTimeout, String name, + boolean failureMode, List configAddrs, long pollConfigIntervalMills) + throws IOException { + super(locator, allocator, conf, socketOptions, commandFactory, transcoder, + getAddressMapFromConfigAddrs(configAddrs), stateListeners, map, poolSize, connectTimeout, + name, failureMode); + if (pollConfigIntervalMills <= 0) { + throw new IllegalArgumentException("Invalid pollConfigIntervalMills value."); + } + // Use failure mode by default. + this.commandFactory = commandFactory; + this.setFailureMode(true); + this.configAddrs = configAddrs; + this.configPoller = new ConfigurationPoller(this, pollConfigIntervalMills); + // Run at once to get config at startup. + // It will call onUpdate in the same thread. + this.configPoller.run(); + if (this.currentClusterConfiguration == null) { + throw new IllegalStateException( + "Retrieve ElasticCache config from `" + configAddrs.toString() + "` failed."); + } + this.configPoller.start(); + } + + private volatile ClusterConfigration currentClusterConfiguration; + + /** + * Get cluster config from cache node by network command. + * + * @return + */ + public ClusterConfigration getConfig() + throws MemcachedException, InterruptedException, TimeoutException { + return this.getConfig("cluster"); + } + + /** + * Get config by key from cache node by network command. + * + * @since 2.3.0 + * @return clusetr config. + */ + public ClusterConfigration getConfig(String key) + throws MemcachedException, InterruptedException, TimeoutException { + Command cmd = this.commandFactory.createAWSElasticCacheConfigCommand("get", key); + final Session session = this.sendCommand(cmd); + this.latchWait(cmd, opTimeout, session); + cmd.getIoBuffer().free(); + this.checkException(cmd); + String result = (String) cmd.getResult(); + if (result == null) { + throw new MemcachedException("Operation fail,may be caused by networking or timeout"); + } + return AWSUtils.parseConfiguration(result); + } + + @Override + protected void shutdown0() { + super.shutdown0(); + if (this.configPoller != null) { + try { + this.configPoller.stop(); + } catch (Exception e) { + // ignore + } + } + } + + /** + * Get the current using configuration in memory. + * + * @since 2.3.0 + * @return current cluster config. + */ + public ClusterConfigration getCurrentConfig() { + return this.currentClusterConfiguration; + } +} diff --git a/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClientBuilder.java b/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClientBuilder.java index 4635aa5a0..dbb72724e 100644 --- a/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClientBuilder.java +++ b/src/main/java/net/rubyeye/xmemcached/aws/AWSElasticCacheClientBuilder.java @@ -1,112 +1,108 @@ -package net.rubyeye.xmemcached.aws; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.List; - -import net.rubyeye.xmemcached.XMemcachedClientBuilder; -import net.rubyeye.xmemcached.utils.AddrUtil; - -/** - * AWSElasticCacheClient builder. - * - * @author dennis - * - */ -public class AWSElasticCacheClientBuilder extends XMemcachedClientBuilder { - - /** - * Returns pollConfigIntervalMs. - * - * @return - */ - public long getPollConfigIntervalMs() { - return pollConfigIntervalMs; - } - - /** - * Set poll config interval in milliseconds. - * - * @param pollConfigIntervalMs - */ - public void setPollConfigIntervalMs(long pollConfigIntervalMs) { - this.pollConfigIntervalMs = pollConfigIntervalMs; - } - - /** - * Returns initial ElasticCache server addresses. - * - * @return - */ - public List getConfigAddrs() { - return configAddrs; - } - - /** - * Set initial ElasticCache server addresses. - * - * @param configAddrs - */ - public void setConfigAddrs(List configAddrs) { - this.configAddrs = configAddrs; - } - - private List configAddrs; - - private long pollConfigIntervalMs = AWSElasticCacheClient.DEFAULT_POLL_CONFIG_INTERVAL_MS; - - /** - * Create a builder with an initial ElasticCache server list string in the - * form of "host:port host2:port". - * - * @param serverList - * server list string in the form of "host:port host2:port" - */ - public AWSElasticCacheClientBuilder(String serverList) { - this(AddrUtil.getAddresses(serverList)); - } - - /** - * Create a builder with an initial ElasticCache server. - * - * @param addr - */ - public AWSElasticCacheClientBuilder(InetSocketAddress addr) { - this(asList(addr)); - } - - private static List asList(InetSocketAddress addr) { - List ret = new ArrayList(); - ret.add(addr); - return ret; - } - - /** - * Create a builder with initial ElasticCache server addresses. - * - * @param configAddrs - */ - public AWSElasticCacheClientBuilder(List configAddrs) { - super(configAddrs); - this.configAddrs = configAddrs; - } - - /** - * Returns a new instanceof AWSElasticCacheClient. - */ - @Override - public AWSElasticCacheClient build() throws IOException { - - AWSElasticCacheClient memcachedClient = new AWSElasticCacheClient( - this.sessionLocator, this.bufferAllocator, this.configuration, - this.socketOptions, this.commandFactory, this.transcoder, - this.stateListeners, this.authInfoMap, this.connectionPoolSize, - this.connectTimeout, this.name, this.failureMode, configAddrs, - this.pollConfigIntervalMs); - this.configureClient(memcachedClient); - - return memcachedClient; - } - -} +package net.rubyeye.xmemcached.aws; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.List; +import net.rubyeye.xmemcached.XMemcachedClientBuilder; +import net.rubyeye.xmemcached.utils.AddrUtil; + +/** + * AWSElasticCacheClient builder. + * + * @author dennis + * + */ +public class AWSElasticCacheClientBuilder extends XMemcachedClientBuilder { + + /** + * Returns pollConfigIntervalMs. + * + * @return + */ + public long getPollConfigIntervalMs() { + return pollConfigIntervalMs; + } + + /** + * Set poll config interval in milliseconds. + * + * @param pollConfigIntervalMs + */ + public void setPollConfigIntervalMs(long pollConfigIntervalMs) { + this.pollConfigIntervalMs = pollConfigIntervalMs; + } + + /** + * Returns initial ElasticCache server addresses. + * + * @return + */ + public List getConfigAddrs() { + return configAddrs; + } + + /** + * Set initial ElasticCache server addresses. + * + * @param configAddrs + */ + public void setConfigAddrs(List configAddrs) { + this.configAddrs = configAddrs; + } + + private List configAddrs; + + private long pollConfigIntervalMs = AWSElasticCacheClient.DEFAULT_POLL_CONFIG_INTERVAL_MS; + + /** + * Create a builder with an initial ElasticCache server list string in the form of "host:port + * host2:port". + * + * @param serverList server list string in the form of "host:port host2:port" + */ + public AWSElasticCacheClientBuilder(String serverList) { + this(AddrUtil.getAddresses(serverList)); + } + + /** + * Create a builder with an initial ElasticCache server. + * + * @param addr + */ + public AWSElasticCacheClientBuilder(InetSocketAddress addr) { + this(asList(addr)); + } + + private static List asList(InetSocketAddress addr) { + List ret = new ArrayList(); + ret.add(addr); + return ret; + } + + /** + * Create a builder with initial ElasticCache server addresses. + * + * @param configAddrs + */ + public AWSElasticCacheClientBuilder(List configAddrs) { + super(configAddrs); + this.configAddrs = configAddrs; + } + + /** + * Returns a new instanceof AWSElasticCacheClient. + */ + @Override + public AWSElasticCacheClient build() throws IOException { + + AWSElasticCacheClient memcachedClient = new AWSElasticCacheClient(this.sessionLocator, + this.bufferAllocator, this.configuration, this.socketOptions, this.commandFactory, + this.transcoder, this.stateListeners, this.authInfoMap, this.connectionPoolSize, + this.connectTimeout, this.name, this.failureMode, configAddrs, this.pollConfigIntervalMs); + this.configureClient(memcachedClient); + + return memcachedClient; + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/aws/AWSUtils.java b/src/main/java/net/rubyeye/xmemcached/aws/AWSUtils.java index c34a81f81..d6a5ac56b 100644 --- a/src/main/java/net/rubyeye/xmemcached/aws/AWSUtils.java +++ b/src/main/java/net/rubyeye/xmemcached/aws/AWSUtils.java @@ -1,62 +1,59 @@ -package net.rubyeye.xmemcached.aws; - -import java.util.ArrayList; -import java.util.List; - -import net.rubyeye.xmemcached.utils.ByteUtils; - -/** - * AWS get config command - * - * @author dennis - * - */ -public class AWSUtils { - - private static final String DELIMITER = "|"; - - /** - * Parse response string to ClusterConfiguration instance. - * - * @param line - * @return - */ - public static ClusterConfigration parseConfiguration(String line) { - String[] lines = line.trim().split("(?:\\r?\\n)"); - if (lines.length < 2) { - throw new IllegalArgumentException( - "Incorrect config response:" + line); - } - String configversion = lines[0]; - String nodeListStr = lines[1]; - if (!ByteUtils.isNumber(configversion)) { - throw new IllegalArgumentException("Invalid configversion: " - + configversion + ", it should be a number."); - } - String[] nodeStrs = nodeListStr.split("(?:\\s)+"); - int version = Integer.parseInt(configversion); - List nodeList = new ArrayList(nodeStrs.length); - for (String nodeStr : nodeStrs) { - if (nodeStr.equals("")) { - continue; - } - - int firstDelimiter = nodeStr.indexOf(DELIMITER); - int secondDelimiter = nodeStr.lastIndexOf(DELIMITER); - if (firstDelimiter < 1 || firstDelimiter == secondDelimiter) { - throw new IllegalArgumentException("Invalid server ''" + nodeStr - + "'' in response: " + line); - } - String hostName = nodeStr.substring(0, firstDelimiter).trim(); - String ipAddress = nodeStr - .substring(firstDelimiter + 1, secondDelimiter).trim(); - String portNum = nodeStr.substring(secondDelimiter + 1).trim(); - int port = Integer.parseInt(portNum); - nodeList.add(new CacheNode(hostName, ipAddress, port)); - } - - return new ClusterConfigration(version, nodeList); - - } - -} +package net.rubyeye.xmemcached.aws; + +import java.util.ArrayList; +import java.util.List; +import net.rubyeye.xmemcached.utils.ByteUtils; + +/** + * AWS get config command + * + * @author dennis + * + */ +public class AWSUtils { + + private static final String DELIMITER = "|"; + + /** + * Parse response string to ClusterConfiguration instance. + * + * @param line + * @return + */ + public static ClusterConfigration parseConfiguration(String line) { + String[] lines = line.trim().split("(?:\\r?\\n)"); + if (lines.length < 2) { + throw new IllegalArgumentException("Incorrect config response:" + line); + } + String configversion = lines[0]; + String nodeListStr = lines[1]; + if (!ByteUtils.isNumber(configversion)) { + throw new IllegalArgumentException( + "Invalid configversion: " + configversion + ", it should be a number."); + } + String[] nodeStrs = nodeListStr.split("(?:\\s)+"); + int version = Integer.parseInt(configversion); + List nodeList = new ArrayList(nodeStrs.length); + for (String nodeStr : nodeStrs) { + if (nodeStr.equals("")) { + continue; + } + + int firstDelimiter = nodeStr.indexOf(DELIMITER); + int secondDelimiter = nodeStr.lastIndexOf(DELIMITER); + if (firstDelimiter < 1 || firstDelimiter == secondDelimiter) { + throw new IllegalArgumentException( + "Invalid server ''" + nodeStr + "'' in response: " + line); + } + String hostName = nodeStr.substring(0, firstDelimiter).trim(); + String ipAddress = nodeStr.substring(firstDelimiter + 1, secondDelimiter).trim(); + String portNum = nodeStr.substring(secondDelimiter + 1).trim(); + int port = Integer.parseInt(portNum); + nodeList.add(new CacheNode(hostName, ipAddress, port)); + } + + return new ClusterConfigration(version, nodeList); + + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/aws/CacheNode.java b/src/main/java/net/rubyeye/xmemcached/aws/CacheNode.java index 4688edcc8..55b06508d 100644 --- a/src/main/java/net/rubyeye/xmemcached/aws/CacheNode.java +++ b/src/main/java/net/rubyeye/xmemcached/aws/CacheNode.java @@ -1,97 +1,94 @@ -package net.rubyeye.xmemcached.aws; - -import java.io.Serializable; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.UnknownHostException; - -import net.rubyeye.xmemcached.utils.ByteUtils; - -/** - * AWS ElasticCache Node information. - * - * @author dennis - * - */ -public class CacheNode implements Serializable { - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result - + ((hostName == null) ? 0 : hostName.hashCode()); - result = prime * result + port; - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - CacheNode other = (CacheNode) obj; - if (hostName == null) { - if (other.hostName != null) - return false; - } else if (!hostName.equals(other.hostName)) - return false; - if (port != other.port) - return false; - return true; - } - - private static final long serialVersionUID = -2999058612548153786L; - - public String getHostName() { - return hostName; - } - - public void setHostName(String hostName) { - this.hostName = hostName; - } - - public InetSocketAddress getInetSocketAddress() { - return new InetSocketAddress(hostName, port); - } - - public String getIpAddress() { - return ipAddress; - } - - public void setIpAddress(String ipAddress) { - this.ipAddress = ipAddress; - } - - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } - - public String toString() { - return "[" + this.hostName + "|" + this.ipAddress + "|" + this.port - + "]"; - } - - public String getCacheKey() { - return this.hostName + ":" + this.port; - } - - private String hostName; - private String ipAddress; - private int port; - - public CacheNode(String hostName, String ipAddress, int port) { - super(); - this.hostName = hostName; - this.ipAddress = ipAddress; - this.port = port; - } - -} +package net.rubyeye.xmemcached.aws; + +import java.io.Serializable; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; +import net.rubyeye.xmemcached.utils.ByteUtils; + +/** + * AWS ElasticCache Node information. + * + * @author dennis + * + */ +public class CacheNode implements Serializable { + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((hostName == null) ? 0 : hostName.hashCode()); + result = prime * result + port; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + CacheNode other = (CacheNode) obj; + if (hostName == null) { + if (other.hostName != null) + return false; + } else if (!hostName.equals(other.hostName)) + return false; + if (port != other.port) + return false; + return true; + } + + private static final long serialVersionUID = -2999058612548153786L; + + public String getHostName() { + return hostName; + } + + public void setHostName(String hostName) { + this.hostName = hostName; + } + + public InetSocketAddress getInetSocketAddress() { + return new InetSocketAddress(hostName, port); + } + + public String getIpAddress() { + return ipAddress; + } + + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public String toString() { + return "[" + this.hostName + "|" + this.ipAddress + "|" + this.port + "]"; + } + + public String getCacheKey() { + return this.hostName + ":" + this.port; + } + + private String hostName; + private String ipAddress; + private int port; + + public CacheNode(String hostName, String ipAddress, int port) { + super(); + this.hostName = hostName; + this.ipAddress = ipAddress; + this.port = port; + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/aws/ClusterConfigration.java b/src/main/java/net/rubyeye/xmemcached/aws/ClusterConfigration.java index 87159edf5..0182dafff 100644 --- a/src/main/java/net/rubyeye/xmemcached/aws/ClusterConfigration.java +++ b/src/main/java/net/rubyeye/xmemcached/aws/ClusterConfigration.java @@ -1,53 +1,52 @@ -package net.rubyeye.xmemcached.aws; - -import java.io.Serializable; -import java.util.List; - -/** - * Cluster configuration retrieved from ElasticCache. - * - * @author dennis - * - */ -public class ClusterConfigration implements Serializable { - - private static final long serialVersionUID = 6809891639636689050L; - - public int getVersion() { - return version; - } - - public void setVersion(int version) { - this.version = version; - } - - public List getNodeList() { - return nodeList; - } - - public void setNodeList(List nodeList) { - this.nodeList = nodeList; - } - - private int version; - private List nodeList; - - public ClusterConfigration(int version, List nodeList) { - super(); - this.version = version; - this.nodeList = nodeList; - } - - public ClusterConfigration() { - super(); - } - - public String toString() { - StringBuilder nodeList = new StringBuilder( - "{ Version: " + version + ", CacheNode List: "); - nodeList.append(this.nodeList); - nodeList.append("}"); - - return nodeList.toString(); - } -} +package net.rubyeye.xmemcached.aws; + +import java.io.Serializable; +import java.util.List; + +/** + * Cluster configuration retrieved from ElasticCache. + * + * @author dennis + * + */ +public class ClusterConfigration implements Serializable { + + private static final long serialVersionUID = 6809891639636689050L; + + public int getVersion() { + return version; + } + + public void setVersion(int version) { + this.version = version; + } + + public List getNodeList() { + return nodeList; + } + + public void setNodeList(List nodeList) { + this.nodeList = nodeList; + } + + private int version; + private List nodeList; + + public ClusterConfigration(int version, List nodeList) { + super(); + this.version = version; + this.nodeList = nodeList; + } + + public ClusterConfigration() { + super(); + } + + public String toString() { + StringBuilder nodeList = new StringBuilder("{ Version: " + version + ", CacheNode List: "); + nodeList.append(this.nodeList); + nodeList.append("}"); + + return nodeList.toString(); + } +} diff --git a/src/main/java/net/rubyeye/xmemcached/aws/ConfigUpdateListener.java b/src/main/java/net/rubyeye/xmemcached/aws/ConfigUpdateListener.java index 9fbeeb07e..bd3830989 100644 --- a/src/main/java/net/rubyeye/xmemcached/aws/ConfigUpdateListener.java +++ b/src/main/java/net/rubyeye/xmemcached/aws/ConfigUpdateListener.java @@ -1,18 +1,17 @@ -package net.rubyeye.xmemcached.aws; - -/** - * AWS ElasticCache config update event listener. - * - * @author dennis - * - */ -public interface ConfigUpdateListener { - - /** - * Called when config is changed. - * - * @param config - * the new config - */ - public void onUpdate(ClusterConfigration config); -} +package net.rubyeye.xmemcached.aws; + +/** + * AWS ElasticCache config update event listener. + * + * @author dennis + * + */ +public interface ConfigUpdateListener { + + /** + * Called when config is changed. + * + * @param config the new config + */ + public void onUpdate(ClusterConfigration config); +} diff --git a/src/main/java/net/rubyeye/xmemcached/aws/ConfigurationPoller.java b/src/main/java/net/rubyeye/xmemcached/aws/ConfigurationPoller.java index 2ff068009..13b58e0ab 100644 --- a/src/main/java/net/rubyeye/xmemcached/aws/ConfigurationPoller.java +++ b/src/main/java/net/rubyeye/xmemcached/aws/ConfigurationPoller.java @@ -1,118 +1,110 @@ -package net.rubyeye.xmemcached.aws; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * AWS ElastiCache configuration poller - * - * @author dennis - * - */ -public class ConfigurationPoller implements Runnable { - - /** - * Return current ClusterConfigration. - * - * @return - */ - public ClusterConfigration getClusterConfiguration() { - return clusterConfigration; - } - - private final AtomicInteger serverOrderCounter = new AtomicInteger(0); - - private Map ordersMap = new HashMap(); - - public synchronized int getCacheNodeOrder(CacheNode node) { - Integer order = this.ordersMap.get(node.getCacheKey()); - if (order != null) { - return order; - } - order = this.serverOrderCounter.incrementAndGet(); - this.ordersMap.put(node.getCacheKey(), order); - return order; - } - - public synchronized void removeCacheNodeOrder(CacheNode node) { - this.ordersMap.remove(node.getCacheKey()); - } - - private static final Logger log = LoggerFactory - .getLogger(ConfigurationPoller.class); - - private final AWSElasticCacheClient client; - - private final long pollIntervalMills; - - private ScheduledExecutorService scheduledExecutorService; - - private volatile ClusterConfigration clusterConfigration = null; - - public ConfigurationPoller(AWSElasticCacheClient client, - long pollIntervalMills) { - super(); - this.client = client; - this.pollIntervalMills = pollIntervalMills; - this.scheduledExecutorService = Executors - .newSingleThreadScheduledExecutor(new ThreadFactory() { - - public Thread newThread(Runnable r) { - Thread t = new Thread(r, "AWSElasticCacheConfigPoller"); - t.setDaemon(true); - if (t.getPriority() != Thread.NORM_PRIORITY) { - t.setPriority(Thread.NORM_PRIORITY); - } - return t; - } - }); - } - - public void start() { - this.scheduledExecutorService.scheduleWithFixedDelay(this, - this.pollIntervalMills, this.pollIntervalMills, - TimeUnit.MILLISECONDS); - } - - public void stop() { - this.scheduledExecutorService.shutdown(); - } - - public void run() { - try { - ClusterConfigration newConfig = this.client.getConfig(); - if (newConfig != null) { - ClusterConfigration currentConfig = this.clusterConfigration; - if (currentConfig == null) { - this.clusterConfigration = newConfig; - } else { - if (newConfig.getVersion() < currentConfig.getVersion()) { - log.warn( - "Ignored new config from ElasticCache node, it's too old, current version is: " - + currentConfig.getVersion() - + ", but the new version is: " - + newConfig.getVersion()); - return; - } else { - this.clusterConfigration = newConfig; - } - } - log.info("Retrieved new config from ElasticCache node: " - + this.clusterConfigration); - this.client.onUpdate(newConfig); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } catch (Exception e) { - log.error("Poll config from ElasticCache node failed", e); - } - } -} +package net.rubyeye.xmemcached.aws; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * AWS ElastiCache configuration poller + * + * @author dennis + * + */ +public class ConfigurationPoller implements Runnable { + + /** + * Return current ClusterConfigration. + * + * @return + */ + public ClusterConfigration getClusterConfiguration() { + return clusterConfigration; + } + + private final AtomicInteger serverOrderCounter = new AtomicInteger(0); + + private Map ordersMap = new HashMap(); + + public synchronized int getCacheNodeOrder(CacheNode node) { + Integer order = this.ordersMap.get(node.getCacheKey()); + if (order != null) { + return order; + } + order = this.serverOrderCounter.incrementAndGet(); + this.ordersMap.put(node.getCacheKey(), order); + return order; + } + + public synchronized void removeCacheNodeOrder(CacheNode node) { + this.ordersMap.remove(node.getCacheKey()); + } + + private static final Logger log = LoggerFactory.getLogger(ConfigurationPoller.class); + + private final AWSElasticCacheClient client; + + private final long pollIntervalMills; + + private ScheduledExecutorService scheduledExecutorService; + + private volatile ClusterConfigration clusterConfigration = null; + + public ConfigurationPoller(AWSElasticCacheClient client, long pollIntervalMills) { + super(); + this.client = client; + this.pollIntervalMills = pollIntervalMills; + this.scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { + + public Thread newThread(Runnable r) { + Thread t = new Thread(r, "AWSElasticCacheConfigPoller"); + t.setDaemon(true); + if (t.getPriority() != Thread.NORM_PRIORITY) { + t.setPriority(Thread.NORM_PRIORITY); + } + return t; + } + }); + } + + public void start() { + this.scheduledExecutorService.scheduleWithFixedDelay(this, this.pollIntervalMills, + this.pollIntervalMills, TimeUnit.MILLISECONDS); + } + + public void stop() { + this.scheduledExecutorService.shutdown(); + } + + public void run() { + try { + ClusterConfigration newConfig = this.client.getConfig(); + if (newConfig != null) { + ClusterConfigration currentConfig = this.clusterConfigration; + if (currentConfig == null) { + this.clusterConfigration = newConfig; + } else { + if (newConfig.getVersion() < currentConfig.getVersion()) { + log.warn("Ignored new config from ElasticCache node, it's too old, current version is: " + + currentConfig.getVersion() + ", but the new version is: " + + newConfig.getVersion()); + return; + } else { + this.clusterConfigration = newConfig; + } + } + log.info("Retrieved new config from ElasticCache node: " + this.clusterConfigration); + this.client.onUpdate(newConfig); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } catch (Exception e) { + log.error("Poll config from ElasticCache node failed", e); + } + } +} diff --git a/src/main/java/net/rubyeye/xmemcached/buffer/BufferAllocator.java b/src/main/java/net/rubyeye/xmemcached/buffer/BufferAllocator.java index 55cd5d0fd..20cf8b9a7 100644 --- a/src/main/java/net/rubyeye/xmemcached/buffer/BufferAllocator.java +++ b/src/main/java/net/rubyeye/xmemcached/buffer/BufferAllocator.java @@ -1,13 +1,10 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.buffer; @@ -20,9 +17,9 @@ */ @Deprecated public interface BufferAllocator { - public IoBuffer allocate(int capacity); + public IoBuffer allocate(int capacity); - public IoBuffer wrap(ByteBuffer byteBuffer); + public IoBuffer wrap(ByteBuffer byteBuffer); - public void dispose(); + public void dispose(); } diff --git a/src/main/java/net/rubyeye/xmemcached/buffer/CachedBufferAllocator.java b/src/main/java/net/rubyeye/xmemcached/buffer/CachedBufferAllocator.java index 1c42984e4..1e72e5984 100644 --- a/src/main/java/net/rubyeye/xmemcached/buffer/CachedBufferAllocator.java +++ b/src/main/java/net/rubyeye/xmemcached/buffer/CachedBufferAllocator.java @@ -1,285 +1,267 @@ -/** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 - */ -/** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 net.rubyeye.xmemcached.buffer; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.HashMap; -import java.util.Map; -import java.util.Queue; - -import net.rubyeye.xmemcached.utils.ByteUtils; - -import com.google.code.yanf4j.util.CircularQueue; - -/** - * Cached IoBuffer allocator,cached buffer in ThreadLocal. - * - * @author dennis - * - */ -@Deprecated -public class CachedBufferAllocator implements BufferAllocator { - - private static final int DEFAULT_MAX_POOL_SIZE = 8; - private static final int DEFAULT_MAX_CACHED_BUFFER_SIZE = 1 << 18; // 256KB - private final int maxPoolSize; - private final int maxCachedBufferSize; - private final ThreadLocal>> heapBuffers; - private final IoBuffer EMPTY_IO_BUFFER = new CachedBufferAllocator.CachedIoBuffer( - ByteBuffer.allocate(0)); - - /** - * Creates a new instance with the default parameters ({@literal - * #DEFAULT_MAX_POOL_SIZE} and {@literal #DEFAULT_MAX_CACHED_BUFFER_SIZE}). - */ - public CachedBufferAllocator() { - this(DEFAULT_MAX_POOL_SIZE, DEFAULT_MAX_CACHED_BUFFER_SIZE); - } - - /** - * Creates a new instance. - * - * @param maxPoolSize - * the maximum number of buffers with the same capacity per - * thread. 0 disables this limitation. - * @param maxCachedBufferSize - * the maximum capacity of a cached buffer. A buffer whose - * capacity is bigger than this value is not pooled. 0 - * disables this limitation. - */ - public CachedBufferAllocator(int maxPoolSize, int maxCachedBufferSize) { - if (maxPoolSize < 0) { - throw new IllegalArgumentException("maxPoolSize: " + maxPoolSize); - } - if (maxCachedBufferSize < 0) { - throw new IllegalArgumentException( - "maxCachedBufferSize: " + maxCachedBufferSize); - } - - this.maxPoolSize = maxPoolSize; - this.maxCachedBufferSize = maxCachedBufferSize; - - this.heapBuffers = new ThreadLocal>>() { - - @Override - protected Map> initialValue() { - return newPoolMap(); - } - }; - } - - public int getMaxPoolSize() { - return this.maxPoolSize; - } - - public int getMaxCachedBufferSize() { - return this.maxCachedBufferSize; - } - - /** - * 初始化缓冲池 - * - * @return - */ - private Map> newPoolMap() { - Map> poolMap = new HashMap>(); - int poolSize = this.maxPoolSize == 0 - ? DEFAULT_MAX_POOL_SIZE - : this.maxPoolSize; - for (int i = 0; i < 31; i++) { - poolMap.put(1 << i, new CircularQueue(poolSize)); - } - poolMap.put(0, new CircularQueue(poolSize)); - poolMap.put(Integer.MAX_VALUE, - new CircularQueue(poolSize)); - return poolMap; - } - - public final IoBuffer allocate(int requestedCapacity) { - if (requestedCapacity == 0) { - return this.EMPTY_IO_BUFFER; - } - // 圆整requestedCapacity到2的x次方 - int actualCapacity = ByteUtils.normalizeCapacity(requestedCapacity); - IoBuffer buf; - if (this.maxCachedBufferSize != 0 - && actualCapacity > this.maxCachedBufferSize) { - buf = wrap(ByteBuffer.allocate(actualCapacity)); - } else { - Queue pool; - pool = this.heapBuffers.get().get(actualCapacity); - // 从池中取 - buf = pool.poll(); - if (buf != null) { - buf.clear(); - } else { - buf = wrap(ByteBuffer.allocate(actualCapacity)); - } - } - buf.limit(requestedCapacity); - return buf; - } - - public final IoBuffer wrap(ByteBuffer nioBuffer) { - return new CachedIoBuffer(nioBuffer); - } - - public void dispose() { - this.heapBuffers.remove(); - } - - public static BufferAllocator newInstance() { - return new CachedBufferAllocator(); - } - - public static BufferAllocator newInstance(int maxPoolSize, - int maxCachedBufferSize) { - return new CachedBufferAllocator(maxPoolSize, maxCachedBufferSize); - } - - public class CachedIoBuffer implements IoBuffer { - - Thread ownerThread; // 所分配的线程 - ByteBuffer origBuffer; - - public CachedIoBuffer(ByteBuffer origBuffer) { - super(); - this.ownerThread = Thread.currentThread(); - this.origBuffer = origBuffer; - } - - public void putInt(int i) { - this.origBuffer.putInt(i); - - } - - public void putShort(short s) { - this.origBuffer.putShort(s); - } - - public ByteOrder order() { - return this.origBuffer.order(); - } - - public boolean isDirect() { - return this.origBuffer.isDirect(); - } - - public void order(ByteOrder byteOrder) { - this.origBuffer.order(byteOrder); - } - - public void putLong(long l) { - this.origBuffer.putLong(l); - - } - - public final void free() { - if (this.origBuffer == null || this.origBuffer - .capacity() > CachedBufferAllocator.this.maxCachedBufferSize - || Thread.currentThread() != this.ownerThread) { - return; - } - - // Add to the cache. - Queue pool; - pool = CachedBufferAllocator.this.heapBuffers.get() - .get(this.origBuffer.capacity()); - if (pool == null) { - return; - } - // 防止OOM - if (CachedBufferAllocator.this.maxPoolSize == 0 - || pool.size() < CachedBufferAllocator.this.maxPoolSize) { - pool.offer(new CachedIoBuffer(this.origBuffer)); - } - this.origBuffer = null; - - } - - public final ByteBuffer[] getByteBuffers() { - return new ByteBuffer[]{this.origBuffer}; - } - - public final void put(byte[] bytes) { - this.origBuffer.put(bytes); - } - - public final int capacity() { - return this.origBuffer.capacity(); - } - - public final void clear() { - this.origBuffer.clear(); - } - - public final void reset() { - this.origBuffer.reset(); - } - - public final int remaining() { - return this.origBuffer.remaining(); - } - - public final int position() { - return this.origBuffer.position(); - } - - public final void mark() { - this.origBuffer.mark(); - } - - public final int limit() { - return this.origBuffer.limit(); - } - - public final boolean hasRemaining() { - return this.origBuffer.hasRemaining(); - } - - public final void flip() { - this.origBuffer.flip(); - } - - public final void put(byte b) { - this.origBuffer.put(b); - } - - public final void put(ByteBuffer buff) { - this.origBuffer.put(buff); - } - - public final ByteBuffer getByteBuffer() { - return this.origBuffer; - } - - public final void limit(int limit) { - this.origBuffer.limit(limit); - } - - public final void position(int pos) { - this.origBuffer.position(pos); - } - } -} +/** + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 + */ +/** + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.buffer; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.HashMap; +import java.util.Map; +import java.util.Queue; +import net.rubyeye.xmemcached.utils.ByteUtils; +import com.google.code.yanf4j.util.CircularQueue; + +/** + * Cached IoBuffer allocator,cached buffer in ThreadLocal. + * + * @author dennis + * + */ +@Deprecated +public class CachedBufferAllocator implements BufferAllocator { + + private static final int DEFAULT_MAX_POOL_SIZE = 8; + private static final int DEFAULT_MAX_CACHED_BUFFER_SIZE = 1 << 18; // 256KB + private final int maxPoolSize; + private final int maxCachedBufferSize; + private final ThreadLocal>> heapBuffers; + private final IoBuffer EMPTY_IO_BUFFER = + new CachedBufferAllocator.CachedIoBuffer(ByteBuffer.allocate(0)); + + /** + * Creates a new instance with the default parameters ({@literal #DEFAULT_MAX_POOL_SIZE} and + * {@literal #DEFAULT_MAX_CACHED_BUFFER_SIZE}). + */ + public CachedBufferAllocator() { + this(DEFAULT_MAX_POOL_SIZE, DEFAULT_MAX_CACHED_BUFFER_SIZE); + } + + /** + * Creates a new instance. + * + * @param maxPoolSize the maximum number of buffers with the same capacity per thread. 0 + * disables this limitation. + * @param maxCachedBufferSize the maximum capacity of a cached buffer. A buffer whose capacity is + * bigger than this value is not pooled. 0 disables this limitation. + */ + public CachedBufferAllocator(int maxPoolSize, int maxCachedBufferSize) { + if (maxPoolSize < 0) { + throw new IllegalArgumentException("maxPoolSize: " + maxPoolSize); + } + if (maxCachedBufferSize < 0) { + throw new IllegalArgumentException("maxCachedBufferSize: " + maxCachedBufferSize); + } + + this.maxPoolSize = maxPoolSize; + this.maxCachedBufferSize = maxCachedBufferSize; + + this.heapBuffers = new ThreadLocal>>() { + + @Override + protected Map> initialValue() { + return newPoolMap(); + } + }; + } + + public int getMaxPoolSize() { + return this.maxPoolSize; + } + + public int getMaxCachedBufferSize() { + return this.maxCachedBufferSize; + } + + /** + * 初始化缓冲池 + * + * @return + */ + private Map> newPoolMap() { + Map> poolMap = new HashMap>(); + int poolSize = this.maxPoolSize == 0 ? DEFAULT_MAX_POOL_SIZE : this.maxPoolSize; + for (int i = 0; i < 31; i++) { + poolMap.put(1 << i, new CircularQueue(poolSize)); + } + poolMap.put(0, new CircularQueue(poolSize)); + poolMap.put(Integer.MAX_VALUE, new CircularQueue(poolSize)); + return poolMap; + } + + public final IoBuffer allocate(int requestedCapacity) { + if (requestedCapacity == 0) { + return this.EMPTY_IO_BUFFER; + } + // 圆整requestedCapacity到2的x次方 + int actualCapacity = ByteUtils.normalizeCapacity(requestedCapacity); + IoBuffer buf; + if (this.maxCachedBufferSize != 0 && actualCapacity > this.maxCachedBufferSize) { + buf = wrap(ByteBuffer.allocate(actualCapacity)); + } else { + Queue pool; + pool = this.heapBuffers.get().get(actualCapacity); + // 从池中取 + buf = pool.poll(); + if (buf != null) { + buf.clear(); + } else { + buf = wrap(ByteBuffer.allocate(actualCapacity)); + } + } + buf.limit(requestedCapacity); + return buf; + } + + public final IoBuffer wrap(ByteBuffer nioBuffer) { + return new CachedIoBuffer(nioBuffer); + } + + public void dispose() { + this.heapBuffers.remove(); + } + + public static BufferAllocator newInstance() { + return new CachedBufferAllocator(); + } + + public static BufferAllocator newInstance(int maxPoolSize, int maxCachedBufferSize) { + return new CachedBufferAllocator(maxPoolSize, maxCachedBufferSize); + } + + public class CachedIoBuffer implements IoBuffer { + + Thread ownerThread; // 所分配的线程 + ByteBuffer origBuffer; + + public CachedIoBuffer(ByteBuffer origBuffer) { + super(); + this.ownerThread = Thread.currentThread(); + this.origBuffer = origBuffer; + } + + public void putInt(int i) { + this.origBuffer.putInt(i); + + } + + public void putShort(short s) { + this.origBuffer.putShort(s); + } + + public ByteOrder order() { + return this.origBuffer.order(); + } + + public boolean isDirect() { + return this.origBuffer.isDirect(); + } + + public void order(ByteOrder byteOrder) { + this.origBuffer.order(byteOrder); + } + + public void putLong(long l) { + this.origBuffer.putLong(l); + + } + + public final void free() { + if (this.origBuffer == null + || this.origBuffer.capacity() > CachedBufferAllocator.this.maxCachedBufferSize + || Thread.currentThread() != this.ownerThread) { + return; + } + + // Add to the cache. + Queue pool; + pool = CachedBufferAllocator.this.heapBuffers.get().get(this.origBuffer.capacity()); + if (pool == null) { + return; + } + // 防止OOM + if (CachedBufferAllocator.this.maxPoolSize == 0 + || pool.size() < CachedBufferAllocator.this.maxPoolSize) { + pool.offer(new CachedIoBuffer(this.origBuffer)); + } + this.origBuffer = null; + + } + + public final ByteBuffer[] getByteBuffers() { + return new ByteBuffer[] {this.origBuffer}; + } + + public final void put(byte[] bytes) { + this.origBuffer.put(bytes); + } + + public final int capacity() { + return this.origBuffer.capacity(); + } + + public final void clear() { + this.origBuffer.clear(); + } + + public final void reset() { + this.origBuffer.reset(); + } + + public final int remaining() { + return this.origBuffer.remaining(); + } + + public final int position() { + return this.origBuffer.position(); + } + + public final void mark() { + this.origBuffer.mark(); + } + + public final int limit() { + return this.origBuffer.limit(); + } + + public final boolean hasRemaining() { + return this.origBuffer.hasRemaining(); + } + + public final void flip() { + this.origBuffer.flip(); + } + + public final void put(byte b) { + this.origBuffer.put(b); + } + + public final void put(ByteBuffer buff) { + this.origBuffer.put(buff); + } + + public final ByteBuffer getByteBuffer() { + return this.origBuffer; + } + + public final void limit(int limit) { + this.origBuffer.limit(limit); + } + + public final void position(int pos) { + this.origBuffer.position(pos); + } + } +} diff --git a/src/main/java/net/rubyeye/xmemcached/buffer/IoBuffer.java b/src/main/java/net/rubyeye/xmemcached/buffer/IoBuffer.java index 1cffee0fc..9eb891ad3 100644 --- a/src/main/java/net/rubyeye/xmemcached/buffer/IoBuffer.java +++ b/src/main/java/net/rubyeye/xmemcached/buffer/IoBuffer.java @@ -1,13 +1,10 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.buffer; @@ -23,49 +20,49 @@ @Deprecated public interface IoBuffer { - int capacity(); + int capacity(); - void clear(); + void clear(); - void flip(); + void flip(); - void free(); + void free(); - ByteBuffer getByteBuffer(); + ByteBuffer getByteBuffer(); - ByteBuffer[] getByteBuffers(); + ByteBuffer[] getByteBuffers(); - boolean hasRemaining(); + boolean hasRemaining(); - int limit(); + int limit(); - void limit(int limit); + void limit(int limit); - void mark(); + void mark(); - int position(); + int position(); - void position(int pos); + void position(int pos); - void put(ByteBuffer buff); + void put(ByteBuffer buff); - void put(byte b); + void put(byte b); - void putShort(short s); + void putShort(short s); - void putInt(int i); + void putInt(int i); - void putLong(long l); + void putLong(long l); - void put(byte[] bytes); + void put(byte[] bytes); - int remaining(); + int remaining(); - void reset(); + void reset(); - boolean isDirect(); + boolean isDirect(); - void order(ByteOrder byteOrder); + void order(ByteOrder byteOrder); - ByteOrder order(); + ByteOrder order(); } diff --git a/src/main/java/net/rubyeye/xmemcached/buffer/SimpleBufferAllocator.java b/src/main/java/net/rubyeye/xmemcached/buffer/SimpleBufferAllocator.java index a082e6d24..5fdd11c10 100644 --- a/src/main/java/net/rubyeye/xmemcached/buffer/SimpleBufferAllocator.java +++ b/src/main/java/net/rubyeye/xmemcached/buffer/SimpleBufferAllocator.java @@ -1,47 +1,42 @@ -/** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 net.rubyeye.xmemcached.buffer; - -import java.nio.ByteBuffer; - -/** - * Simple IoBuffer allocator,allcate a new heap ByteBuffer each time. - * - * @author dennis - * - */ -@Deprecated -public class SimpleBufferAllocator implements BufferAllocator { - - public static final IoBuffer EMPTY_IOBUFFER = new SimpleIoBuffer( - ByteBuffer.allocate(0)); - - public final IoBuffer allocate(int capacity) { - if (capacity == 0) { - return EMPTY_IOBUFFER; - } else { - return wrap(ByteBuffer.allocate(capacity)); - } - } - - public final void dispose() { - } - - public final static BufferAllocator newInstance() { - return new SimpleBufferAllocator(); - } - - public final IoBuffer wrap(ByteBuffer byteBuffer) { - return new SimpleIoBuffer(byteBuffer); - } - -} +/** + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.buffer; + +import java.nio.ByteBuffer; + +/** + * Simple IoBuffer allocator,allcate a new heap ByteBuffer each time. + * + * @author dennis + * + */ +@Deprecated +public class SimpleBufferAllocator implements BufferAllocator { + + public static final IoBuffer EMPTY_IOBUFFER = new SimpleIoBuffer(ByteBuffer.allocate(0)); + + public final IoBuffer allocate(int capacity) { + if (capacity == 0) { + return EMPTY_IOBUFFER; + } else { + return wrap(ByteBuffer.allocate(capacity)); + } + } + + public final void dispose() {} + + public final static BufferAllocator newInstance() { + return new SimpleBufferAllocator(); + } + + public final IoBuffer wrap(ByteBuffer byteBuffer) { + return new SimpleIoBuffer(byteBuffer); + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/buffer/SimpleIoBuffer.java b/src/main/java/net/rubyeye/xmemcached/buffer/SimpleIoBuffer.java index 989eeeeab..8dee4b4fe 100644 --- a/src/main/java/net/rubyeye/xmemcached/buffer/SimpleIoBuffer.java +++ b/src/main/java/net/rubyeye/xmemcached/buffer/SimpleIoBuffer.java @@ -1,121 +1,120 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.buffer; + /** * Simpe ByteBuffer Wrapper */ import java.nio.ByteBuffer; import java.nio.ByteOrder; + @Deprecated public class SimpleIoBuffer implements IoBuffer { - protected ByteBuffer origBuffer; + protected ByteBuffer origBuffer; - public SimpleIoBuffer(ByteBuffer origBuffer) { - this.origBuffer = origBuffer; - } + public SimpleIoBuffer(ByteBuffer origBuffer) { + this.origBuffer = origBuffer; + } - public final void free() { - this.origBuffer = null; - } + public final void free() { + this.origBuffer = null; + } - public final ByteBuffer[] getByteBuffers() { - return new ByteBuffer[]{this.origBuffer}; - } + public final ByteBuffer[] getByteBuffers() { + return new ByteBuffer[] {this.origBuffer}; + } - public final void put(byte[] bytes) { - this.origBuffer.put(bytes); - } + public final void put(byte[] bytes) { + this.origBuffer.put(bytes); + } - public final int capacity() { - return this.origBuffer.capacity(); - } + public final int capacity() { + return this.origBuffer.capacity(); + } - public void putInt(int i) { - this.origBuffer.putInt(i); + public void putInt(int i) { + this.origBuffer.putInt(i); - } + } - public void putShort(short s) { - this.origBuffer.putShort(s); - } + public void putShort(short s) { + this.origBuffer.putShort(s); + } - public final void clear() { - this.origBuffer.clear(); - } + public final void clear() { + this.origBuffer.clear(); + } - public final void reset() { - this.origBuffer.reset(); - } + public final void reset() { + this.origBuffer.reset(); + } - public final int remaining() { - return this.origBuffer.remaining(); - } + public final int remaining() { + return this.origBuffer.remaining(); + } - public final int position() { - return this.origBuffer.position(); - } + public final int position() { + return this.origBuffer.position(); + } - public final void mark() { - this.origBuffer.mark(); - } + public final void mark() { + this.origBuffer.mark(); + } - public final int limit() { - return this.origBuffer.limit(); - } + public final int limit() { + return this.origBuffer.limit(); + } - public final boolean hasRemaining() { - return this.origBuffer.hasRemaining(); - } + public final boolean hasRemaining() { + return this.origBuffer.hasRemaining(); + } - public final void flip() { - this.origBuffer.flip(); - } + public final void flip() { + this.origBuffer.flip(); + } - public final void put(byte b) { - this.origBuffer.put(b); - } + public final void put(byte b) { + this.origBuffer.put(b); + } - public final void put(ByteBuffer buff) { - this.origBuffer.put(buff); - } + public final void put(ByteBuffer buff) { + this.origBuffer.put(buff); + } - public final ByteBuffer getByteBuffer() { - return this.origBuffer; - } + public final ByteBuffer getByteBuffer() { + return this.origBuffer; + } - public final void limit(int limit) { - this.origBuffer.limit(limit); - } + public final void limit(int limit) { + this.origBuffer.limit(limit); + } - public final void position(int pos) { - this.origBuffer.position(pos); - } + public final void position(int pos) { + this.origBuffer.position(pos); + } - public void order(ByteOrder byteOrder) { - this.origBuffer.order(byteOrder); - } + public void order(ByteOrder byteOrder) { + this.origBuffer.order(byteOrder); + } - public boolean isDirect() { - return this.origBuffer.isDirect(); - } + public boolean isDirect() { + return this.origBuffer.isDirect(); + } - public ByteOrder order() { - return this.origBuffer.order(); - } + public ByteOrder order() { + return this.origBuffer.order(); + } - public void putLong(long l) { - this.origBuffer.putLong(l); + public void putLong(long l) { + this.origBuffer.putLong(l); - } + } } diff --git a/src/main/java/net/rubyeye/xmemcached/buffer/package.html b/src/main/java/net/rubyeye/xmemcached/buffer/package.html index 5316b096b..3ca09d3eb 100644 --- a/src/main/java/net/rubyeye/xmemcached/buffer/package.html +++ b/src/main/java/net/rubyeye/xmemcached/buffer/package.html @@ -1,15 +1,10 @@ - - + - -ByteBuffer Wrapper(Deprecated) - - - -

ByteBuffer Wrapper,all classes of this package has been -deprecated.

- - - + + ByteBuffer Wrapper(Deprecated) + + +

ByteBuffer Wrapper,all classes of this package has been deprecated.

+ + \ No newline at end of file diff --git a/src/main/java/net/rubyeye/xmemcached/codec/MemcachedCodecFactory.java b/src/main/java/net/rubyeye/xmemcached/codec/MemcachedCodecFactory.java index ee403236f..f3fd392fb 100644 --- a/src/main/java/net/rubyeye/xmemcached/codec/MemcachedCodecFactory.java +++ b/src/main/java/net/rubyeye/xmemcached/codec/MemcachedCodecFactory.java @@ -1,13 +1,10 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.codec; @@ -22,30 +19,30 @@ */ public class MemcachedCodecFactory implements CodecFactory { - private final MemcachedEncoder encoder; + private final MemcachedEncoder encoder; - private final MemcachedDecoder decoder; + private final MemcachedDecoder decoder; - public MemcachedCodecFactory() { - super(); - this.encoder = new MemcachedEncoder(); - this.decoder = new MemcachedDecoder(); - } + public MemcachedCodecFactory() { + super(); + this.encoder = new MemcachedEncoder(); + this.decoder = new MemcachedDecoder(); + } - /** - * return the memcached protocol decoder - */ + /** + * return the memcached protocol decoder + */ - public final CodecFactory.Decoder getDecoder() { - return this.decoder; + public final CodecFactory.Decoder getDecoder() { + return this.decoder; - } + } - /** - * return the memcached protocol encoder - */ + /** + * return the memcached protocol encoder + */ - public final CodecFactory.Encoder getEncoder() { - return this.encoder; - } + public final CodecFactory.Encoder getEncoder() { + return this.encoder; + } } diff --git a/src/main/java/net/rubyeye/xmemcached/codec/MemcachedDecoder.java b/src/main/java/net/rubyeye/xmemcached/codec/MemcachedDecoder.java index f81ca2739..35eb13495 100644 --- a/src/main/java/net/rubyeye/xmemcached/codec/MemcachedDecoder.java +++ b/src/main/java/net/rubyeye/xmemcached/codec/MemcachedDecoder.java @@ -1,23 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.codec; import net.rubyeye.xmemcached.command.Command; import net.rubyeye.xmemcached.impl.MemcachedTCPSession; import net.rubyeye.xmemcached.utils.ByteUtils; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import com.google.code.yanf4j.buffer.IoBuffer; import com.google.code.yanf4j.core.Session; import com.google.code.yanf4j.core.CodecFactory.Decoder; @@ -32,37 +27,36 @@ */ public class MemcachedDecoder implements Decoder { - public static final Logger log = LoggerFactory - .getLogger(MemcachedDecoder.class); - - public MemcachedDecoder() { - super(); - } - - /** - * shift-and algorithm for ByteBuffer's match - */ - public static final ByteBufferMatcher SPLIT_MATCHER = new ShiftAndByteBufferMatcher( - IoBuffer.wrap(ByteUtils.SPLIT)); - - public Object decode(IoBuffer buffer, Session origSession) { - MemcachedTCPSession session = (MemcachedTCPSession) origSession; - if (session.getCurrentCommand() != null) { - return decode0(buffer, session); - } else { - session.takeCurrentCommand(); - if (session.getCurrentCommand() == null) - return null; - return decode0(buffer, session); - } - } - - private Object decode0(IoBuffer buffer, MemcachedTCPSession session) { - if (session.getCurrentCommand().decode(session, buffer.buf())) { - final Command command = session.getCurrentCommand(); - session.setCurrentCommand(null); - return command; - } - return null; - } + public static final Logger log = LoggerFactory.getLogger(MemcachedDecoder.class); + + public MemcachedDecoder() { + super(); + } + + /** + * shift-and algorithm for ByteBuffer's match + */ + public static final ByteBufferMatcher SPLIT_MATCHER = + new ShiftAndByteBufferMatcher(IoBuffer.wrap(ByteUtils.SPLIT)); + + public Object decode(IoBuffer buffer, Session origSession) { + MemcachedTCPSession session = (MemcachedTCPSession) origSession; + if (session.getCurrentCommand() != null) { + return decode0(buffer, session); + } else { + session.takeCurrentCommand(); + if (session.getCurrentCommand() == null) + return null; + return decode0(buffer, session); + } + } + + private Object decode0(IoBuffer buffer, MemcachedTCPSession session) { + if (session.getCurrentCommand().decode(session, buffer.buf())) { + final Command command = session.getCurrentCommand(); + session.setCurrentCommand(null); + return command; + } + return null; + } } diff --git a/src/main/java/net/rubyeye/xmemcached/codec/MemcachedEncoder.java b/src/main/java/net/rubyeye/xmemcached/codec/MemcachedEncoder.java index 9d58eb729..af8e12277 100644 --- a/src/main/java/net/rubyeye/xmemcached/codec/MemcachedEncoder.java +++ b/src/main/java/net/rubyeye/xmemcached/codec/MemcachedEncoder.java @@ -1,18 +1,14 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.codec; import net.rubyeye.xmemcached.command.Command; - import com.google.code.yanf4j.buffer.IoBuffer; import com.google.code.yanf4j.core.Session; import com.google.code.yanf4j.core.CodecFactory.Encoder; @@ -25,8 +21,8 @@ */ public class MemcachedEncoder implements Encoder { - public IoBuffer encode(Object message, Session session) { - return ((Command) message).getIoBuffer(); - } + public IoBuffer encode(Object message, Session session) { + return ((Command) message).getIoBuffer(); + } } diff --git a/src/main/java/net/rubyeye/xmemcached/codec/package.html b/src/main/java/net/rubyeye/xmemcached/codec/package.html index 4fa21fb0a..034b3b7b6 100644 --- a/src/main/java/net/rubyeye/xmemcached/codec/package.html +++ b/src/main/java/net/rubyeye/xmemcached/codec/package.html @@ -1,14 +1,10 @@ - - + - -Memcached protocol codec - - - -

Memcached protocol codec

- - - + + Memcached protocol codec + + +

Memcached protocol codec

+ + \ No newline at end of file diff --git a/src/main/java/net/rubyeye/xmemcached/command/AssocCommandAware.java b/src/main/java/net/rubyeye/xmemcached/command/AssocCommandAware.java index cf6715465..1e8f41d8d 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/AssocCommandAware.java +++ b/src/main/java/net/rubyeye/xmemcached/command/AssocCommandAware.java @@ -3,14 +3,13 @@ import java.util.List; /** - * Assoc commands aware interface.Association commands mean that commands has - * the same key. + * Assoc commands aware interface.Association commands mean that commands has the same key. * * @author dennis * */ public interface AssocCommandAware { - public List getAssocCommands(); + public List getAssocCommands(); - public void setAssocCommands(List assocCommands); + public void setAssocCommands(List assocCommands); } diff --git a/src/main/java/net/rubyeye/xmemcached/command/BinaryCommandFactory.java b/src/main/java/net/rubyeye/xmemcached/command/BinaryCommandFactory.java index a293ed4f9..251292851 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/BinaryCommandFactory.java +++ b/src/main/java/net/rubyeye/xmemcached/command/BinaryCommandFactory.java @@ -6,7 +6,6 @@ import java.util.Iterator; import java.util.List; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.CommandFactory; import net.rubyeye.xmemcached.buffer.BufferAllocator; import net.rubyeye.xmemcached.buffer.SimpleBufferAllocator; @@ -32,7 +31,6 @@ import net.rubyeye.xmemcached.transcoders.Transcoder; import net.rubyeye.xmemcached.utils.ByteUtils; import net.rubyeye.xmemcached.utils.Protocol; - import com.google.code.yanf4j.buffer.IoBuffer; /** @@ -44,172 +42,153 @@ @SuppressWarnings("unchecked") public class BinaryCommandFactory implements CommandFactory { - public Command createAWSElasticCacheConfigCommand(String subCommand, - String key) { - return new BinaryAWSElasticCacheConfigCommand(new CountDownLatch(1), - subCommand, key); - } - - private BufferAllocator bufferAllocator = new SimpleBufferAllocator(); - - public void setBufferAllocator(BufferAllocator bufferAllocator) { - this.bufferAllocator = bufferAllocator; - } - - public Command createAddCommand(String key, byte[] keyBytes, int exp, - Object value, boolean noreply, Transcoder transcoder) { - return this.createStoreCommand(key, keyBytes, exp, value, - CommandType.ADD, noreply, transcoder); - } - - public Command createAppendCommand(String key, byte[] keyBytes, - Object value, boolean noreply, Transcoder transcoder) { - return new BinaryAppendPrependCommand(key, keyBytes, CommandType.APPEND, - new CountDownLatch(1), 0, 0, value, noreply, transcoder); - } - - public Command createCASCommand(String key, byte[] keyBytes, int exp, - Object value, long cas, boolean noreply, Transcoder transcoder) { - return new BinaryCASCommand(key, keyBytes, CommandType.CAS, - new CountDownLatch(1), exp, cas, value, noreply, transcoder); - } - - public Command createDeleteCommand(String key, byte[] keyBytes, int time, - long cas, boolean noreply) { - return new BinaryDeleteCommand(key, keyBytes, cas, CommandType.DELETE, - new CountDownLatch(1), noreply); - } - - public Command createFlushAllCommand(CountDownLatch latch, int delay, - boolean noreply) { - return new BinaryFlushAllCommand(latch, delay, noreply); - } - - public Command createGetCommand(String key, byte[] keyBytes, - CommandType cmdType, Transcoder transcoder) { - return new BinaryGetCommand(key, keyBytes, cmdType, - new CountDownLatch(1), OpCode.GET, false); - } - - public Command createGetMultiCommand(Collection keys, - CountDownLatch latch, CommandType cmdType, - Transcoder transcoder) { - Iterator it = keys.iterator(); - String key = null; - List bufferList = new ArrayList(); - int totalLength = 0; - while (it.hasNext()) { - key = it.next(); - if (it.hasNext()) { - // first n-1 send getq command - Command command = new BinaryGetCommand(key, - ByteUtils.getBytes(key), cmdType, null, - OpCode.GET_KEY_QUIETLY, true); - command.encode(); - totalLength += command.getIoBuffer().remaining(); - bufferList.add(command.getIoBuffer()); - } - } - // last key,create a get command - Command lastCommand = new BinaryGetCommand(key, ByteUtils.getBytes(key), - cmdType, new CountDownLatch(1), OpCode.GET_KEY, false); - lastCommand.encode(); - bufferList.add(lastCommand.getIoBuffer()); - totalLength += lastCommand.getIoBuffer().remaining(); - - IoBuffer mergedBuffer = IoBuffer.allocate(totalLength); - for (IoBuffer buffer : bufferList) { - mergedBuffer.put(buffer.buf()); - } - mergedBuffer.flip(); - Command resultCommand = new BinaryGetMultiCommand(key, cmdType, latch); - resultCommand.setIoBuffer(mergedBuffer); - return resultCommand; - } - - public Command createIncrDecrCommand(String key, byte[] keyBytes, - long amount, long initial, int expTime, CommandType cmdType, - boolean noreply) { - return new BinaryIncrDecrCommand(key, keyBytes, amount, initial, - expTime, cmdType, noreply); - } - - public Command createPrependCommand(String key, byte[] keyBytes, - Object value, boolean noreply, Transcoder transcoder) { - return new BinaryAppendPrependCommand(key, keyBytes, - CommandType.PREPEND, new CountDownLatch(1), 0, 0, value, - noreply, transcoder); - } - - public Command createReplaceCommand(String key, byte[] keyBytes, int exp, - Object value, boolean noreply, Transcoder transcoder) { - return this.createStoreCommand(key, keyBytes, exp, value, - CommandType.REPLACE, noreply, transcoder); - } - - final Command createStoreCommand(String key, byte[] keyBytes, int exp, - Object value, CommandType cmdType, boolean noreply, - Transcoder transcoder) { - return new BinaryStoreCommand(key, keyBytes, cmdType, - new CountDownLatch(1), exp, -1, value, noreply, transcoder); - } - - public Command createSetCommand(String key, byte[] keyBytes, int exp, - Object value, boolean noreply, Transcoder transcoder) { - return this.createStoreCommand(key, keyBytes, exp, value, - CommandType.SET, noreply, transcoder); - } - - public Command createStatsCommand(InetSocketAddress server, - CountDownLatch latch, String itemName) { - return new BinaryStatsCommand(server, latch, itemName); - } - - public Command createVerbosityCommand(CountDownLatch latch, int level, - boolean noreply) { - return new BinaryVerbosityCommand(latch, level, noreply); - } - - public Command createVersionCommand(CountDownLatch latch, - InetSocketAddress server) { - return new BinaryVersionCommand(latch, server); - } - - public Command createAuthListMechanismsCommand(CountDownLatch latch) { - return new BinaryAuthListMechanismsCommand(latch); - } - - public Command createAuthStartCommand(String mechanism, - CountDownLatch latch, byte[] authData) { - return new BinaryAuthStartCommand(mechanism, - ByteUtils.getBytes(mechanism), latch, authData); - } - - public Command createAuthStepCommand(String mechanism, CountDownLatch latch, - byte[] authData) { - return new BinaryAuthStepCommand(mechanism, - ByteUtils.getBytes(mechanism), latch, authData); - } - - public Command createGetAndTouchCommand(String key, byte[] keyBytes, - CountDownLatch latch, int exp, boolean noreply) { - return new BinaryGetAndTouchCommand(key, keyBytes, - noreply ? CommandType.GATQ : CommandType.GAT, latch, exp, - noreply); - } - - public Command createTouchCommand(String key, byte[] keyBytes, - CountDownLatch latch, int exp, boolean noreply) { - return new BinaryTouchCommand(key, keyBytes, CommandType.TOUCH, latch, - exp, noreply); - } - - public Command createQuitCommand() { - return new BinaryQuitCommand(); - } - - public Protocol getProtocol() { - return Protocol.Binary; - } + public Command createAWSElasticCacheConfigCommand(String subCommand, String key) { + return new BinaryAWSElasticCacheConfigCommand(new CountDownLatch(1), subCommand, key); + } + + private BufferAllocator bufferAllocator = new SimpleBufferAllocator(); + + public void setBufferAllocator(BufferAllocator bufferAllocator) { + this.bufferAllocator = bufferAllocator; + } + + public Command createAddCommand(String key, byte[] keyBytes, int exp, Object value, + boolean noreply, Transcoder transcoder) { + return this.createStoreCommand(key, keyBytes, exp, value, CommandType.ADD, noreply, transcoder); + } + + public Command createAppendCommand(String key, byte[] keyBytes, Object value, boolean noreply, + Transcoder transcoder) { + return new BinaryAppendPrependCommand(key, keyBytes, CommandType.APPEND, new CountDownLatch(1), + 0, 0, value, noreply, transcoder); + } + + public Command createCASCommand(String key, byte[] keyBytes, int exp, Object value, long cas, + boolean noreply, Transcoder transcoder) { + return new BinaryCASCommand(key, keyBytes, CommandType.CAS, new CountDownLatch(1), exp, cas, + value, noreply, transcoder); + } + + public Command createDeleteCommand(String key, byte[] keyBytes, int time, long cas, + boolean noreply) { + return new BinaryDeleteCommand(key, keyBytes, cas, CommandType.DELETE, new CountDownLatch(1), + noreply); + } + + public Command createFlushAllCommand(CountDownLatch latch, int delay, boolean noreply) { + return new BinaryFlushAllCommand(latch, delay, noreply); + } + + public Command createGetCommand(String key, byte[] keyBytes, CommandType cmdType, + Transcoder transcoder) { + return new BinaryGetCommand(key, keyBytes, cmdType, new CountDownLatch(1), OpCode.GET, false); + } + + public Command createGetMultiCommand(Collection keys, CountDownLatch latch, + CommandType cmdType, Transcoder transcoder) { + Iterator it = keys.iterator(); + String key = null; + List bufferList = + new ArrayList(); + int totalLength = 0; + while (it.hasNext()) { + key = it.next(); + if (it.hasNext()) { + // first n-1 send getq command + Command command = new BinaryGetCommand(key, ByteUtils.getBytes(key), cmdType, null, + OpCode.GET_KEY_QUIETLY, true); + command.encode(); + totalLength += command.getIoBuffer().remaining(); + bufferList.add(command.getIoBuffer()); + } + } + // last key,create a get command + Command lastCommand = new BinaryGetCommand(key, ByteUtils.getBytes(key), cmdType, + new CountDownLatch(1), OpCode.GET_KEY, false); + lastCommand.encode(); + bufferList.add(lastCommand.getIoBuffer()); + totalLength += lastCommand.getIoBuffer().remaining(); + + IoBuffer mergedBuffer = IoBuffer.allocate(totalLength); + for (IoBuffer buffer : bufferList) { + mergedBuffer.put(buffer.buf()); + } + mergedBuffer.flip(); + Command resultCommand = new BinaryGetMultiCommand(key, cmdType, latch); + resultCommand.setIoBuffer(mergedBuffer); + return resultCommand; + } + + public Command createIncrDecrCommand(String key, byte[] keyBytes, long amount, long initial, + int expTime, CommandType cmdType, boolean noreply) { + return new BinaryIncrDecrCommand(key, keyBytes, amount, initial, expTime, cmdType, noreply); + } + + public Command createPrependCommand(String key, byte[] keyBytes, Object value, boolean noreply, + Transcoder transcoder) { + return new BinaryAppendPrependCommand(key, keyBytes, CommandType.PREPEND, new CountDownLatch(1), + 0, 0, value, noreply, transcoder); + } + + public Command createReplaceCommand(String key, byte[] keyBytes, int exp, Object value, + boolean noreply, Transcoder transcoder) { + return this.createStoreCommand(key, keyBytes, exp, value, CommandType.REPLACE, noreply, + transcoder); + } + + final Command createStoreCommand(String key, byte[] keyBytes, int exp, Object value, + CommandType cmdType, boolean noreply, Transcoder transcoder) { + return new BinaryStoreCommand(key, keyBytes, cmdType, new CountDownLatch(1), exp, -1, value, + noreply, transcoder); + } + + public Command createSetCommand(String key, byte[] keyBytes, int exp, Object value, + boolean noreply, Transcoder transcoder) { + return this.createStoreCommand(key, keyBytes, exp, value, CommandType.SET, noreply, transcoder); + } + + public Command createStatsCommand(InetSocketAddress server, CountDownLatch latch, + String itemName) { + return new BinaryStatsCommand(server, latch, itemName); + } + + public Command createVerbosityCommand(CountDownLatch latch, int level, boolean noreply) { + return new BinaryVerbosityCommand(latch, level, noreply); + } + + public Command createVersionCommand(CountDownLatch latch, InetSocketAddress server) { + return new BinaryVersionCommand(latch, server); + } + + public Command createAuthListMechanismsCommand(CountDownLatch latch) { + return new BinaryAuthListMechanismsCommand(latch); + } + + public Command createAuthStartCommand(String mechanism, CountDownLatch latch, byte[] authData) { + return new BinaryAuthStartCommand(mechanism, ByteUtils.getBytes(mechanism), latch, authData); + } + + public Command createAuthStepCommand(String mechanism, CountDownLatch latch, byte[] authData) { + return new BinaryAuthStepCommand(mechanism, ByteUtils.getBytes(mechanism), latch, authData); + } + + public Command createGetAndTouchCommand(String key, byte[] keyBytes, CountDownLatch latch, + int exp, boolean noreply) { + return new BinaryGetAndTouchCommand(key, keyBytes, noreply ? CommandType.GATQ : CommandType.GAT, + latch, exp, noreply); + } + + public Command createTouchCommand(String key, byte[] keyBytes, CountDownLatch latch, int exp, + boolean noreply) { + return new BinaryTouchCommand(key, keyBytes, CommandType.TOUCH, latch, exp, noreply); + } + + public Command createQuitCommand() { + return new BinaryQuitCommand(); + } + + public Protocol getProtocol() { + return Protocol.Binary; + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/Command.java b/src/main/java/net/rubyeye/xmemcached/command/Command.java index ceae5d3f1..a7e15cfe6 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/Command.java +++ b/src/main/java/net/rubyeye/xmemcached/command/Command.java @@ -1,20 +1,16 @@ /** - *Copyright [2009-2010] [dennis zhuang] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang] Licensed 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 net.rubyeye.xmemcached.command; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.exception.MemcachedClientException; import net.rubyeye.xmemcached.exception.MemcachedDecodeException; import net.rubyeye.xmemcached.exception.MemcachedServerException; @@ -22,7 +18,6 @@ import net.rubyeye.xmemcached.impl.MemcachedTCPSession; import net.rubyeye.xmemcached.transcoders.Transcoder; import net.rubyeye.xmemcached.utils.ByteUtils; - import com.google.code.yanf4j.buffer.IoBuffer; import com.google.code.yanf4j.core.Session; import com.google.code.yanf4j.core.WriteMessage; @@ -36,290 +31,279 @@ */ public abstract class Command implements WriteMessage { - public static final byte REQUEST_MAGIC_NUMBER = (byte) (0x80 & 0xFF); - - public static final byte RESPONSE_MAGIC_NUMBER = (byte) (0x81 & 0xFF); - - private boolean added; - - public boolean isAdded() { - return added; - } - - public void setAdded(boolean added) { - this.added = added; - } - - public final Object getMessage() { - return this; - } - - public synchronized final com.google.code.yanf4j.buffer.IoBuffer getWriteBuffer() { - return getIoBuffer(); - } - - public void setWriteBuffer(com.google.code.yanf4j.buffer.IoBuffer buffers) { - // throw new UnsupportedOperationException(); - } - - protected String key; - protected byte[] keyBytes; - protected Object result; - protected CountDownLatch latch; - protected CommandType commandType; - protected Exception exception; - protected IoBuffer ioBuffer; - protected volatile boolean cancel; - protected OperationStatus status; - protected int mergeCount = -1; - private int copiedMergeCount = mergeCount; - @SuppressWarnings("unchecked") - protected Transcoder transcoder; - protected boolean noreply; - protected FutureImpl writeFuture; - - public final byte[] getKeyBytes() { - return keyBytes; - } - - public final void setKeyBytes(byte[] keyBytes) { - this.keyBytes = keyBytes; - } - - public void setCommandType(final CommandType commandType) { - this.commandType = commandType; - } - - public int getMergeCount() { - return mergeCount; - } - - @SuppressWarnings("unchecked") - public Transcoder getTranscoder() { - return transcoder; - } - - @SuppressWarnings("unchecked") - public void setTranscoder(Transcoder transcoder) { - this.transcoder = transcoder; - } - - public void setMergeCount(final int mergetCount) { - mergeCount = mergetCount; - this.copiedMergeCount = mergetCount; - } - - public int getCopiedMergeCount() { - return copiedMergeCount; - } - - public Command() { - super(); - status = OperationStatus.SENDING; - } - - public Command(String key, byte[] keyBytes, CountDownLatch latch) { - super(); - this.key = key; - this.keyBytes = keyBytes; - status = OperationStatus.SENDING; - this.latch = latch; - } - - public Command(String key, byte[] keyBytes, CommandType cmdType, - CountDownLatch latch) { - super(); - this.key = key; - this.keyBytes = keyBytes; - status = OperationStatus.SENDING; - this.latch = latch; - commandType = cmdType; - } - - public Command(final CommandType cmdType) { - commandType = cmdType; - status = OperationStatus.SENDING; - } - - public Command(final CommandType cmdType, final CountDownLatch latch) { - commandType = cmdType; - this.latch = latch; - status = OperationStatus.SENDING; - } - - public Command(final String key, final CommandType commandType, - final CountDownLatch latch) { - super(); - this.key = key; - this.commandType = commandType; - this.latch = latch; - status = OperationStatus.SENDING; - } - - public OperationStatus getStatus() { - return status; - } - - public final void setStatus(OperationStatus status) { - this.status = status; - } - - public final void setIoBuffer(IoBuffer ioBuffer) { - this.ioBuffer = ioBuffer; - } - - public Exception getException() { - return exception; - } - - public void setException(Exception throwable) { - exception = throwable; - } - - public final String getKey() { - return key; - } - - public final void setKey(String key) { - this.key = key; - } - - public final Object getResult() { - return result; - } - - public final void setResult(Object result) { - this.result = result; - } - - public final IoBuffer getIoBuffer() { - return ioBuffer; - } - - @Override - public String toString() { - try { - return new String(ioBuffer.buf().array(), "utf-8"); - } catch (UnsupportedEncodingException e) { - } - return "[error]"; - } - - public boolean isCancel() { - return status == OperationStatus.SENDING && cancel; - } - - public final void cancel() { - cancel = true; - if (ioBuffer != null) { - ioBuffer.free(); - } - } - - public final CountDownLatch getLatch() { - return latch; - } - - public final void countDownLatch() { - if (latch != null) { - latch.countDown(); - if (latch.getCount() == 0) { - status = OperationStatus.DONE; - } - } - } - - public final CommandType getCommandType() { - return commandType; - } - - public final void setLatch(CountDownLatch latch) { - this.latch = latch; - } - - public abstract void encode(); - - public abstract boolean decode(MemcachedTCPSession session, - ByteBuffer buffer); - - protected final void decodeError(String msg, Throwable e) { - throw new MemcachedDecodeException(msg == null - ? "decode error,session will be closed,key=" + this.key - : msg, e); - } - - protected final void decodeError() { - throw new MemcachedDecodeException( - "decode error,session will be closed,key=" + this.key); - } - - protected final boolean decodeError(String line) { - if (line.startsWith("ERROR")) { - String[] splits = line.split("ERROR"); - String errorMsg = splits.length >= 2 - ? splits[1] - : "Unknow command " + getCommandType(); - setException( - new UnknownCommandException("Response error,error message:" - + errorMsg + ",key=" + this.key)); - countDownLatch(); - return true; - } else if (line.startsWith("CLIENT_ERROR")) { - setException(new MemcachedClientException( - getErrorMsg(line, "Unknown Client Error"))); - this.countDownLatch(); - return true; - } else if (line.startsWith("SERVER_ERROR")) { - setException(new MemcachedServerException( - getErrorMsg(line, "Unknown Server Error"))); - this.countDownLatch(); - return true; - } else { - throw new MemcachedDecodeException( - "Decode error,session will be closed,key=" + this.key - + ",server returns=" + line); - } - - } - - protected final boolean decodeError(Session session, ByteBuffer buffer) { - String line = ByteUtils.nextLine(buffer); - if (line == null) { - return false; - } else { - return decodeError(line); - } - } - - private String getErrorMsg(String line, String defaultMsg) { - int index = line.indexOf(" "); - String errorMsg = index > 0 ? line.substring(index + 1) : defaultMsg; - errorMsg += ",key=" + this.key; - return errorMsg; - } - - public final boolean isNoreply() { - return noreply; - } - - public final void setNoreply(boolean noreply) { - this.noreply = noreply; - } - - public FutureImpl getWriteFuture() { - return writeFuture; - } - - public final void setWriteFuture(FutureImpl writeFuture) { - this.writeFuture = writeFuture; - } - - public final boolean isWriting() { - return true; - } - - public final void writing() { - // do nothing - } + public static final byte REQUEST_MAGIC_NUMBER = (byte) (0x80 & 0xFF); + + public static final byte RESPONSE_MAGIC_NUMBER = (byte) (0x81 & 0xFF); + + private boolean added; + + public boolean isAdded() { + return added; + } + + public void setAdded(boolean added) { + this.added = added; + } + + public final Object getMessage() { + return this; + } + + public synchronized final com.google.code.yanf4j.buffer.IoBuffer getWriteBuffer() { + return getIoBuffer(); + } + + public void setWriteBuffer(com.google.code.yanf4j.buffer.IoBuffer buffers) { + // throw new UnsupportedOperationException(); + } + + protected String key; + protected byte[] keyBytes; + protected Object result; + protected CountDownLatch latch; + protected CommandType commandType; + protected Exception exception; + protected IoBuffer ioBuffer; + protected volatile boolean cancel; + protected OperationStatus status; + protected int mergeCount = -1; + private int copiedMergeCount = mergeCount; + @SuppressWarnings("unchecked") + protected Transcoder transcoder; + protected boolean noreply; + protected FutureImpl writeFuture; + + public final byte[] getKeyBytes() { + return keyBytes; + } + + public final void setKeyBytes(byte[] keyBytes) { + this.keyBytes = keyBytes; + } + + public void setCommandType(final CommandType commandType) { + this.commandType = commandType; + } + + public int getMergeCount() { + return mergeCount; + } + + @SuppressWarnings("unchecked") + public Transcoder getTranscoder() { + return transcoder; + } + + @SuppressWarnings("unchecked") + public void setTranscoder(Transcoder transcoder) { + this.transcoder = transcoder; + } + + public void setMergeCount(final int mergetCount) { + mergeCount = mergetCount; + this.copiedMergeCount = mergetCount; + } + + public int getCopiedMergeCount() { + return copiedMergeCount; + } + + public Command() { + super(); + status = OperationStatus.SENDING; + } + + public Command(String key, byte[] keyBytes, CountDownLatch latch) { + super(); + this.key = key; + this.keyBytes = keyBytes; + status = OperationStatus.SENDING; + this.latch = latch; + } + + public Command(String key, byte[] keyBytes, CommandType cmdType, CountDownLatch latch) { + super(); + this.key = key; + this.keyBytes = keyBytes; + status = OperationStatus.SENDING; + this.latch = latch; + commandType = cmdType; + } + + public Command(final CommandType cmdType) { + commandType = cmdType; + status = OperationStatus.SENDING; + } + + public Command(final CommandType cmdType, final CountDownLatch latch) { + commandType = cmdType; + this.latch = latch; + status = OperationStatus.SENDING; + } + + public Command(final String key, final CommandType commandType, final CountDownLatch latch) { + super(); + this.key = key; + this.commandType = commandType; + this.latch = latch; + status = OperationStatus.SENDING; + } + + public OperationStatus getStatus() { + return status; + } + + public final void setStatus(OperationStatus status) { + this.status = status; + } + + public final void setIoBuffer(IoBuffer ioBuffer) { + this.ioBuffer = ioBuffer; + } + + public Exception getException() { + return exception; + } + + public void setException(Exception throwable) { + exception = throwable; + } + + public final String getKey() { + return key; + } + + public final void setKey(String key) { + this.key = key; + } + + public final Object getResult() { + return result; + } + + public final void setResult(Object result) { + this.result = result; + } + + public final IoBuffer getIoBuffer() { + return ioBuffer; + } + + @Override + public String toString() { + try { + return new String(ioBuffer.buf().array(), "utf-8"); + } catch (UnsupportedEncodingException e) { + } + return "[error]"; + } + + public boolean isCancel() { + return status == OperationStatus.SENDING && cancel; + } + + public final void cancel() { + cancel = true; + if (ioBuffer != null) { + ioBuffer.free(); + } + } + + public final CountDownLatch getLatch() { + return latch; + } + + public final void countDownLatch() { + if (latch != null) { + latch.countDown(); + if (latch.getCount() == 0) { + status = OperationStatus.DONE; + } + } + } + + public final CommandType getCommandType() { + return commandType; + } + + public final void setLatch(CountDownLatch latch) { + this.latch = latch; + } + + public abstract void encode(); + + public abstract boolean decode(MemcachedTCPSession session, ByteBuffer buffer); + + protected final void decodeError(String msg, Throwable e) { + throw new MemcachedDecodeException( + msg == null ? "decode error,session will be closed,key=" + this.key : msg, e); + } + + protected final void decodeError() { + throw new MemcachedDecodeException("decode error,session will be closed,key=" + this.key); + } + + protected final boolean decodeError(String line) { + if (line.startsWith("ERROR")) { + String[] splits = line.split("ERROR"); + String errorMsg = splits.length >= 2 ? splits[1] : "Unknow command " + getCommandType(); + setException(new UnknownCommandException( + "Response error,error message:" + errorMsg + ",key=" + this.key)); + countDownLatch(); + return true; + } else if (line.startsWith("CLIENT_ERROR")) { + setException(new MemcachedClientException(getErrorMsg(line, "Unknown Client Error"))); + this.countDownLatch(); + return true; + } else if (line.startsWith("SERVER_ERROR")) { + setException(new MemcachedServerException(getErrorMsg(line, "Unknown Server Error"))); + this.countDownLatch(); + return true; + } else { + throw new MemcachedDecodeException( + "Decode error,session will be closed,key=" + this.key + ",server returns=" + line); + } + + } + + protected final boolean decodeError(Session session, ByteBuffer buffer) { + String line = ByteUtils.nextLine(buffer); + if (line == null) { + return false; + } else { + return decodeError(line); + } + } + + private String getErrorMsg(String line, String defaultMsg) { + int index = line.indexOf(" "); + String errorMsg = index > 0 ? line.substring(index + 1) : defaultMsg; + errorMsg += ",key=" + this.key; + return errorMsg; + } + + public final boolean isNoreply() { + return noreply; + } + + public final void setNoreply(boolean noreply) { + this.noreply = noreply; + } + + public FutureImpl getWriteFuture() { + return writeFuture; + } + + public final void setWriteFuture(FutureImpl writeFuture) { + this.writeFuture = writeFuture; + } + + public final boolean isWriting() { + return true; + } + + public final void writing() { + // do nothing + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/CommandType.java b/src/main/java/net/rubyeye/xmemcached/command/CommandType.java index 632728bf0..5d6b5a453 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/CommandType.java +++ b/src/main/java/net/rubyeye/xmemcached/command/CommandType.java @@ -8,8 +8,8 @@ */ public enum CommandType { - NOOP, STATS, FLUSH_ALL, GET_ONE, GET_MANY, SET, REPLACE, ADD, EXCEPTION, // - DELETE, VERSION, QUIT, INCR, DECR, GETS_ONE, GETS_MANY, CAS, APPEND, PREPEND, // - GET_HIT, GET_MISS, VERBOSITY, AUTH_LIST, AUTH_START, AUTH_STEP, TOUCH, GAT, GATQ, SET_MANY, // - AWS_CONFIG; -} \ No newline at end of file + NOOP, STATS, FLUSH_ALL, GET_ONE, GET_MANY, SET, REPLACE, ADD, EXCEPTION, // + DELETE, VERSION, QUIT, INCR, DECR, GETS_ONE, GETS_MANY, CAS, APPEND, PREPEND, // + GET_HIT, GET_MISS, VERBOSITY, AUTH_LIST, AUTH_START, AUTH_STEP, TOUCH, GAT, GATQ, SET_MANY, // + AWS_CONFIG; +} diff --git a/src/main/java/net/rubyeye/xmemcached/command/KestrelCommandFactory.java b/src/main/java/net/rubyeye/xmemcached/command/KestrelCommandFactory.java index 7af8ff7fc..c3ab311b7 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/KestrelCommandFactory.java +++ b/src/main/java/net/rubyeye/xmemcached/command/KestrelCommandFactory.java @@ -3,7 +3,6 @@ import java.net.InetSocketAddress; import java.util.Collection; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.CommandFactory; import net.rubyeye.xmemcached.buffer.BufferAllocator; import net.rubyeye.xmemcached.command.kestrel.KestrelDeleteCommand; @@ -16,11 +15,10 @@ import net.rubyeye.xmemcached.utils.Protocol; /** - * Kestrel is a message queue written in scala by - * robey(http://github.com/robey/kestrel).It's protocol use memcached text - * protocol,so you can use any memcached clients to talk with it.But it's - * protocol implementation is not all compatible with memcached standard - * protocol,So xmemcached supply this command factory for it. + * Kestrel is a message queue written in scala by robey(http://github.com/robey/kestrel).It's + * protocol use memcached text protocol,so you can use any memcached clients to talk with it.But + * it's protocol implementation is not all compatible with memcached standard protocol,So xmemcached + * supply this command factory for it. * * @author dennis * @@ -28,136 +26,113 @@ @SuppressWarnings("unchecked") public class KestrelCommandFactory implements CommandFactory { - public Command createAWSElasticCacheConfigCommand(String subCommand, - String key) { - throw new UnsupportedOperationException( - "Kestrel doesn't support this operation"); - } - - public Command createAddCommand(String key, byte[] keyBytes, int exp, - Object value, boolean noreply, Transcoder transcoder) { - throw new UnsupportedOperationException( - "Kestrel doesn't support this operation"); - } - - public Command createAppendCommand(String key, byte[] keyBytes, - Object value, boolean noreply, Transcoder transcoder) { - throw new UnsupportedOperationException( - "Kestrel doesn't support this operation"); - } - - public Command createCASCommand(String key, byte[] keyBytes, int exp, - Object value, long cas, boolean noreply, Transcoder transcoder) { - throw new UnsupportedOperationException( - "Kestrel doesn't support this operation"); - } - - public Command createDeleteCommand(String key, byte[] keyBytes, int time, - long cas, boolean noreply) { - return new KestrelDeleteCommand(key, keyBytes, -1, - new CountDownLatch(1), noreply); - } - - public Command createFlushAllCommand(CountDownLatch latch, int delay, - boolean noreply) { - return new KestrelFlushAllCommand(latch, delay, noreply); - } - - public Command createGetCommand(String key, byte[] keyBytes, - CommandType cmdType, Transcoder transcoder) { - return new KestrelGetCommand(key, keyBytes, cmdType, - new CountDownLatch(1), transcoder); - } - - public Command createGetMultiCommand(Collection keys, - CountDownLatch latch, CommandType cmdType, - Transcoder transcoder) { - throw new UnsupportedOperationException( - "Kestrel doesn't support this operation"); - } - - public Command createIncrDecrCommand(String key, byte[] keyBytes, - long amount, long initial, int expTime, CommandType cmdType, - boolean noreply) { - throw new UnsupportedOperationException( - "Kestrel doesn't support this operation"); - } - - public Command createPrependCommand(String key, byte[] keyBytes, - Object value, boolean noreply, Transcoder transcoder) { - throw new UnsupportedOperationException( - "Kestrel doesn't support this operation"); - } - - public Command createReplaceCommand(String key, byte[] keyBytes, int exp, - Object value, boolean noreply, Transcoder transcoder) { - throw new UnsupportedOperationException( - "Kestrel doesn't support this operation"); - } - - public Command createSetCommand(String key, byte[] keyBytes, int exp, - Object value, boolean noreply, Transcoder transcoder) { - return new KestrelSetCommand(key, keyBytes, CommandType.SET, - new CountDownLatch(1), exp, -1, value, noreply, transcoder); - } - - public Command createStatsCommand(InetSocketAddress server, - CountDownLatch latch, String itemName) { - if (itemName != null) { - throw new UnsupportedOperationException( - "Kestrel doesn't support 'stats itemName'"); - } - return new TextStatsCommand(server, latch, null); - } - - public Command createVerbosityCommand(CountDownLatch latch, int level, - boolean noreply) { - throw new UnsupportedOperationException( - "Kestrel doesn't support this operation"); - } - - public Command createVersionCommand(CountDownLatch latch, - InetSocketAddress server) { - throw new UnsupportedOperationException( - "Kestrel doesn't support this operation"); - } - - public Command createQuitCommand() { - return new TextQuitCommand(); - } - - public Protocol getProtocol() { - return Protocol.Kestrel; - } - - public Command createAuthListMechanismsCommand(CountDownLatch latch) { - throw new UnsupportedOperationException("Kestrel doesn't support SASL"); - } - - public Command createAuthStartCommand(String mechanism, - CountDownLatch latch, byte[] authData) { - throw new UnsupportedOperationException("Kestrel doesn't support SASL"); - } - - public Command createAuthStepCommand(String mechanism, CountDownLatch latch, - byte[] authData) { - throw new UnsupportedOperationException("Kestrel doesn't support SASL"); - } - - public Command createGetAndTouchCommand(String key, byte[] keyBytes, - CountDownLatch latch, int exp, boolean noreply) { - throw new UnsupportedOperationException( - "GAT is only supported by binary protocol"); - } - - public Command createTouchCommand(String key, byte[] keyBytes, - CountDownLatch latch, int exp, boolean noreply) { - throw new UnsupportedOperationException( - "Touch is only supported by binary protocol"); - } - - public void setBufferAllocator(BufferAllocator bufferAllocator) { - - } + public Command createAWSElasticCacheConfigCommand(String subCommand, String key) { + throw new UnsupportedOperationException("Kestrel doesn't support this operation"); + } + + public Command createAddCommand(String key, byte[] keyBytes, int exp, Object value, + boolean noreply, Transcoder transcoder) { + throw new UnsupportedOperationException("Kestrel doesn't support this operation"); + } + + public Command createAppendCommand(String key, byte[] keyBytes, Object value, boolean noreply, + Transcoder transcoder) { + throw new UnsupportedOperationException("Kestrel doesn't support this operation"); + } + + public Command createCASCommand(String key, byte[] keyBytes, int exp, Object value, long cas, + boolean noreply, Transcoder transcoder) { + throw new UnsupportedOperationException("Kestrel doesn't support this operation"); + } + + public Command createDeleteCommand(String key, byte[] keyBytes, int time, long cas, + boolean noreply) { + return new KestrelDeleteCommand(key, keyBytes, -1, new CountDownLatch(1), noreply); + } + + public Command createFlushAllCommand(CountDownLatch latch, int delay, boolean noreply) { + return new KestrelFlushAllCommand(latch, delay, noreply); + } + + public Command createGetCommand(String key, byte[] keyBytes, CommandType cmdType, + Transcoder transcoder) { + return new KestrelGetCommand(key, keyBytes, cmdType, new CountDownLatch(1), transcoder); + } + + public Command createGetMultiCommand(Collection keys, CountDownLatch latch, + CommandType cmdType, Transcoder transcoder) { + throw new UnsupportedOperationException("Kestrel doesn't support this operation"); + } + + public Command createIncrDecrCommand(String key, byte[] keyBytes, long amount, long initial, + int expTime, CommandType cmdType, boolean noreply) { + throw new UnsupportedOperationException("Kestrel doesn't support this operation"); + } + + public Command createPrependCommand(String key, byte[] keyBytes, Object value, boolean noreply, + Transcoder transcoder) { + throw new UnsupportedOperationException("Kestrel doesn't support this operation"); + } + + public Command createReplaceCommand(String key, byte[] keyBytes, int exp, Object value, + boolean noreply, Transcoder transcoder) { + throw new UnsupportedOperationException("Kestrel doesn't support this operation"); + } + + public Command createSetCommand(String key, byte[] keyBytes, int exp, Object value, + boolean noreply, Transcoder transcoder) { + return new KestrelSetCommand(key, keyBytes, CommandType.SET, new CountDownLatch(1), exp, -1, + value, noreply, transcoder); + } + + public Command createStatsCommand(InetSocketAddress server, CountDownLatch latch, + String itemName) { + if (itemName != null) { + throw new UnsupportedOperationException("Kestrel doesn't support 'stats itemName'"); + } + return new TextStatsCommand(server, latch, null); + } + + public Command createVerbosityCommand(CountDownLatch latch, int level, boolean noreply) { + throw new UnsupportedOperationException("Kestrel doesn't support this operation"); + } + + public Command createVersionCommand(CountDownLatch latch, InetSocketAddress server) { + throw new UnsupportedOperationException("Kestrel doesn't support this operation"); + } + + public Command createQuitCommand() { + return new TextQuitCommand(); + } + + public Protocol getProtocol() { + return Protocol.Kestrel; + } + + public Command createAuthListMechanismsCommand(CountDownLatch latch) { + throw new UnsupportedOperationException("Kestrel doesn't support SASL"); + } + + public Command createAuthStartCommand(String mechanism, CountDownLatch latch, byte[] authData) { + throw new UnsupportedOperationException("Kestrel doesn't support SASL"); + } + + public Command createAuthStepCommand(String mechanism, CountDownLatch latch, byte[] authData) { + throw new UnsupportedOperationException("Kestrel doesn't support SASL"); + } + + public Command createGetAndTouchCommand(String key, byte[] keyBytes, CountDownLatch latch, + int exp, boolean noreply) { + throw new UnsupportedOperationException("GAT is only supported by binary protocol"); + } + + public Command createTouchCommand(String key, byte[] keyBytes, CountDownLatch latch, int exp, + boolean noreply) { + throw new UnsupportedOperationException("Touch is only supported by binary protocol"); + } + + public void setBufferAllocator(BufferAllocator bufferAllocator) { + + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/MapReturnValueAware.java b/src/main/java/net/rubyeye/xmemcached/command/MapReturnValueAware.java index 828f895de..aeaaeda1e 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/MapReturnValueAware.java +++ b/src/main/java/net/rubyeye/xmemcached/command/MapReturnValueAware.java @@ -1,7 +1,6 @@ package net.rubyeye.xmemcached.command; import java.util.Map; - import net.rubyeye.xmemcached.transcoders.CachedData; /** @@ -12,6 +11,6 @@ */ public interface MapReturnValueAware { - public abstract Map getReturnValues(); + public abstract Map getReturnValues(); -} \ No newline at end of file +} diff --git a/src/main/java/net/rubyeye/xmemcached/command/MergeCommandsAware.java b/src/main/java/net/rubyeye/xmemcached/command/MergeCommandsAware.java index ae3662142..f3f47c9bc 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/MergeCommandsAware.java +++ b/src/main/java/net/rubyeye/xmemcached/command/MergeCommandsAware.java @@ -3,16 +3,16 @@ import java.util.Map; /** - * Merge commands aware interface.Merge commands mean that merge get commands to - * a bulk-get commands. + * Merge commands aware interface.Merge commands mean that merge get commands to a bulk-get + * commands. * * @author boyan * */ public interface MergeCommandsAware { - public Map getMergeCommands(); + public Map getMergeCommands(); - public void setMergeCommands(Map mergeCommands); + public void setMergeCommands(Map mergeCommands); } diff --git a/src/main/java/net/rubyeye/xmemcached/command/OperationStatus.java b/src/main/java/net/rubyeye/xmemcached/command/OperationStatus.java index 6d0bb41a1..d01e014ab 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/OperationStatus.java +++ b/src/main/java/net/rubyeye/xmemcached/command/OperationStatus.java @@ -1,10 +1,11 @@ package net.rubyeye.xmemcached.command; + /** * Command status. * * @author dennis - * + * */ public enum OperationStatus { - SENDING, WRITING, SENT, PROCESSING, DONE, CANCEL; + SENDING, WRITING, SENT, PROCESSING, DONE, CANCEL; } diff --git a/src/main/java/net/rubyeye/xmemcached/command/ServerAddressAware.java b/src/main/java/net/rubyeye/xmemcached/command/ServerAddressAware.java index 226ad426c..4a1620f2d 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/ServerAddressAware.java +++ b/src/main/java/net/rubyeye/xmemcached/command/ServerAddressAware.java @@ -4,18 +4,17 @@ import java.nio.ByteBuffer; /** - * Server address aware interface.Command which implement this interface have - * these methods to getter/setter memcached's InetSocketAddress. + * Server address aware interface.Command which implement this interface have these methods to + * getter/setter memcached's InetSocketAddress. * * @author boyan * */ public interface ServerAddressAware { - public static final ByteBuffer VERSION = ByteBuffer - .wrap("version\r\n".getBytes()); + public static final ByteBuffer VERSION = ByteBuffer.wrap("version\r\n".getBytes()); - public InetSocketAddress getServer(); + public InetSocketAddress getServer(); - public void setServer(InetSocketAddress server); + public void setServer(InetSocketAddress server); } diff --git a/src/main/java/net/rubyeye/xmemcached/command/StoreCommand.java b/src/main/java/net/rubyeye/xmemcached/command/StoreCommand.java index 35b7b6218..c66df8b2f 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/StoreCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/StoreCommand.java @@ -1,14 +1,14 @@ -package net.rubyeye.xmemcached.command; - -/** - * A store command interface for STORE commands such as SET,ADD - * - * @author apple - * - */ -public interface StoreCommand { - - public void setValue(Object value); - - public Object getValue(); -} +package net.rubyeye.xmemcached.command; + +/** + * A store command interface for STORE commands such as SET,ADD + * + * @author apple + * + */ +public interface StoreCommand { + + public void setValue(Object value); + + public Object getValue(); +} diff --git a/src/main/java/net/rubyeye/xmemcached/command/TextCommandFactory.java b/src/main/java/net/rubyeye/xmemcached/command/TextCommandFactory.java index 4edcf6e6e..5b1963d5c 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/TextCommandFactory.java +++ b/src/main/java/net/rubyeye/xmemcached/command/TextCommandFactory.java @@ -3,7 +3,6 @@ import java.net.InetSocketAddress; import java.util.Collection; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.CommandFactory; import net.rubyeye.xmemcached.buffer.BufferAllocator; import net.rubyeye.xmemcached.command.text.TextAWSElasticCacheConfigCommand; @@ -31,227 +30,191 @@ */ public class TextCommandFactory implements CommandFactory { - public Command createAWSElasticCacheConfigCommand(String subCommand, - String key) { - return new TextAWSElasticCacheConfigCommand(new CountDownLatch(1), - subCommand, key); - } - - public void setBufferAllocator(BufferAllocator bufferAllocator) { - - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.CommandFactory#createDeleteCommand(java.lang. - * String , byte[], int) - */ - public final Command createDeleteCommand(final String key, - final byte[] keyBytes, final int time, long cas, boolean noreply) { - return new TextDeleteCommand(key, keyBytes, time, new CountDownLatch(1), - noreply); - } - - /* - * (non-Javadoc) - * - * @see net.rubyeye.xmemcached.CommandFactory#createVersionCommand() - */ - public final Command createVersionCommand(CountDownLatch latch, - InetSocketAddress server) { - return new TextVersionCommand(latch, server); - } - - /* - * (non-Javadoc) - * - * @see - * net.rubyeye.xmemcached.CommandFactory#createFlushAllCommand(java.util - * .concurrent.CountDownLatch) - */ - public final Command createFlushAllCommand(CountDownLatch latch, - int exptime, boolean noreply) { - return new TextFlushAllCommand(latch, exptime, noreply); - } - - /** - * Create verbosity command - * - * @param latch - * @param level - * @param noreply - * @return - */ - public final Command createVerbosityCommand(CountDownLatch latch, int level, - boolean noreply) { - return new TextVerbosityCommand(latch, level, noreply); - } - - /* - * (non-Javadoc) - * - * @seenet.rubyeye.xmemcached.CommandFactory#createStatsCommand(java.net. - * InetSocketAddress, java.util.concurrent.CountDownLatch) - */ - public final Command createStatsCommand(InetSocketAddress server, - CountDownLatch latch, String itemName) { - return new TextStatsCommand(server, latch, itemName); - } - - /* - * (non-Javadoc) - * - * @see - * net.rubyeye.xmemcached.CommandFactory#createStoreCommand(java.lang.String - * , byte[], int, java.lang.Object, - * net.rubyeye.xmemcached.command.CommandType, java.lang.String, long, - * net.rubyeye.xmemcached.transcoders.Transcoder) - */ - @SuppressWarnings("unchecked") - public final Command createCASCommand(final String key, - final byte[] keyBytes, final int exp, final Object value, long cas, - boolean noreply, Transcoder transcoder) { - return new TextCASCommand(key, keyBytes, CommandType.CAS, - new CountDownLatch(1), exp, cas, value, noreply, transcoder); - } - - @SuppressWarnings("unchecked") - public final Command createSetCommand(final String key, - final byte[] keyBytes, final int exp, final Object value, - boolean noreply, Transcoder transcoder) { - return this.createStoreCommand(key, keyBytes, exp, value, - CommandType.SET, noreply, transcoder); - } - - @SuppressWarnings("unchecked") - public final Command createAddCommand(final String key, - final byte[] keyBytes, final int exp, final Object value, - boolean noreply, Transcoder transcoder) { - return this.createStoreCommand(key, keyBytes, exp, value, - CommandType.ADD, noreply, transcoder); - } - - @SuppressWarnings("unchecked") - public final Command createReplaceCommand(final String key, - final byte[] keyBytes, final int exp, final Object value, - boolean noreply, Transcoder transcoder) { - return this.createStoreCommand(key, keyBytes, exp, value, - CommandType.REPLACE, noreply, transcoder); - } - - @SuppressWarnings("unchecked") - public final Command createAppendCommand(final String key, - final byte[] keyBytes, final Object value, boolean noreply, - Transcoder transcoder) { - return this.createStoreCommand(key, keyBytes, 0, value, - CommandType.APPEND, noreply, transcoder); - } - - @SuppressWarnings("unchecked") - public final Command createPrependCommand(final String key, - final byte[] keyBytes, final Object value, boolean noreply, - Transcoder transcoder) { - return this.createStoreCommand(key, keyBytes, 0, value, - CommandType.PREPEND, noreply, transcoder); - } - - @SuppressWarnings("unchecked") - final Command createStoreCommand(String key, byte[] keyBytes, int exp, - Object value, CommandType cmdType, boolean noreply, - Transcoder transcoder) { - return new TextStoreCommand(key, keyBytes, cmdType, - new CountDownLatch(1), exp, -1, value, noreply, transcoder); - } - - /* - * (non-Javadoc) - * - * @see - * net.rubyeye.xmemcached.CommandFactory#createGetCommand(java.lang.String, - * byte[], net.rubyeye.xmemcached.command.CommandType) - */ - @SuppressWarnings("unchecked") - public final Command createGetCommand(final String key, - final byte[] keyBytes, final CommandType cmdType, - Transcoder transcoder) { - return new TextGetOneCommand(key, keyBytes, cmdType, - new CountDownLatch(1)); - } - - /* - * (non-Javadoc) - * - * @see - * net.rubyeye.xmemcached.CommandFactory#createGetMultiCommand(java.util - * .Collection, java.util.concurrent.CountDownLatch, - * net.rubyeye.xmemcached.command.CommandType, - * net.rubyeye.xmemcached.transcoders.Transcoder) - */ - public final Command createGetMultiCommand(Collection keys, - CountDownLatch latch, CommandType cmdType, - Transcoder transcoder) { - StringBuilder sb = new StringBuilder(keys.size() * 5); - for (String tmpKey : keys) { - ByteUtils.checkKey(tmpKey); - sb.append(tmpKey).append(" "); - } - String gatherKey = sb.toString(); - byte[] keyBytes = ByteUtils - .getBytes(gatherKey.substring(0, gatherKey.length() - 1)); - return new TextGetMultiCommand(keys.iterator().next(), keyBytes, - cmdType, latch, transcoder); - } - - /* - * (non-Javadoc) - * - * @see - * net.rubyeye.xmemcached.CommandFactory#createIncrDecrCommand(java.lang - * .String, byte[], int, net.rubyeye.xmemcached.command.CommandType) - */ - public final Command createIncrDecrCommand(final String key, - final byte[] keyBytes, final long amount, long initial, int exptime, - CommandType cmdType, boolean noreply) { - return new TextIncrDecrCommand(key, keyBytes, cmdType, - new CountDownLatch(1), amount, initial, noreply); - } - - public Command createAuthListMechanismsCommand(CountDownLatch latch) { - throw new UnsupportedOperationException( - "SASL is only supported by binary protocol"); - } - - public Command createAuthStartCommand(String mechanism, - CountDownLatch latch, byte[] authData) { - throw new UnsupportedOperationException( - "SASL is only supported by binary protocol"); - } - - public Command createAuthStepCommand(String mechanism, CountDownLatch latch, - byte[] authData) { - throw new UnsupportedOperationException( - "SASL is only supported by binary protocol"); - } - - public Command createGetAndTouchCommand(String key, byte[] keyBytes, - CountDownLatch latch, int exp, boolean noreply) { - throw new UnsupportedOperationException( - "GAT is only supported by binary protocol"); - } - - public Command createTouchCommand(String key, byte[] keyBytes, - CountDownLatch latch, int exp, boolean noreply) { - return new TextTouchCommand(key, keyBytes, CommandType.TOUCH, latch, - exp, noreply); - } - - public Command createQuitCommand() { - return new TextQuitCommand(); - } - - public Protocol getProtocol() { - return Protocol.Text; - } + public Command createAWSElasticCacheConfigCommand(String subCommand, String key) { + return new TextAWSElasticCacheConfigCommand(new CountDownLatch(1), subCommand, key); + } + + public void setBufferAllocator(BufferAllocator bufferAllocator) { + + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.CommandFactory#createDeleteCommand(java.lang. String , byte[], int) + */ + public final Command createDeleteCommand(final String key, final byte[] keyBytes, final int time, + long cas, boolean noreply) { + return new TextDeleteCommand(key, keyBytes, time, new CountDownLatch(1), noreply); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.CommandFactory#createVersionCommand() + */ + public final Command createVersionCommand(CountDownLatch latch, InetSocketAddress server) { + return new TextVersionCommand(latch, server); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.CommandFactory#createFlushAllCommand(java.util + * .concurrent.CountDownLatch) + */ + public final Command createFlushAllCommand(CountDownLatch latch, int exptime, boolean noreply) { + return new TextFlushAllCommand(latch, exptime, noreply); + } + + /** + * Create verbosity command + * + * @param latch + * @param level + * @param noreply + * @return + */ + public final Command createVerbosityCommand(CountDownLatch latch, int level, boolean noreply) { + return new TextVerbosityCommand(latch, level, noreply); + } + + /* + * (non-Javadoc) + * + * @seenet.rubyeye.xmemcached.CommandFactory#createStatsCommand(java.net. InetSocketAddress, + * java.util.concurrent.CountDownLatch) + */ + public final Command createStatsCommand(InetSocketAddress server, CountDownLatch latch, + String itemName) { + return new TextStatsCommand(server, latch, itemName); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.CommandFactory#createStoreCommand(java.lang.String , byte[], int, + * java.lang.Object, net.rubyeye.xmemcached.command.CommandType, java.lang.String, long, + * net.rubyeye.xmemcached.transcoders.Transcoder) + */ + @SuppressWarnings("unchecked") + public final Command createCASCommand(final String key, final byte[] keyBytes, final int exp, + final Object value, long cas, boolean noreply, Transcoder transcoder) { + return new TextCASCommand(key, keyBytes, CommandType.CAS, new CountDownLatch(1), exp, cas, + value, noreply, transcoder); + } + + @SuppressWarnings("unchecked") + public final Command createSetCommand(final String key, final byte[] keyBytes, final int exp, + final Object value, boolean noreply, Transcoder transcoder) { + return this.createStoreCommand(key, keyBytes, exp, value, CommandType.SET, noreply, transcoder); + } + + @SuppressWarnings("unchecked") + public final Command createAddCommand(final String key, final byte[] keyBytes, final int exp, + final Object value, boolean noreply, Transcoder transcoder) { + return this.createStoreCommand(key, keyBytes, exp, value, CommandType.ADD, noreply, transcoder); + } + + @SuppressWarnings("unchecked") + public final Command createReplaceCommand(final String key, final byte[] keyBytes, final int exp, + final Object value, boolean noreply, Transcoder transcoder) { + return this.createStoreCommand(key, keyBytes, exp, value, CommandType.REPLACE, noreply, + transcoder); + } + + @SuppressWarnings("unchecked") + public final Command createAppendCommand(final String key, final byte[] keyBytes, + final Object value, boolean noreply, Transcoder transcoder) { + return this.createStoreCommand(key, keyBytes, 0, value, CommandType.APPEND, noreply, + transcoder); + } + + @SuppressWarnings("unchecked") + public final Command createPrependCommand(final String key, final byte[] keyBytes, + final Object value, boolean noreply, Transcoder transcoder) { + return this.createStoreCommand(key, keyBytes, 0, value, CommandType.PREPEND, noreply, + transcoder); + } + + @SuppressWarnings("unchecked") + final Command createStoreCommand(String key, byte[] keyBytes, int exp, Object value, + CommandType cmdType, boolean noreply, Transcoder transcoder) { + return new TextStoreCommand(key, keyBytes, cmdType, new CountDownLatch(1), exp, -1, value, + noreply, transcoder); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.CommandFactory#createGetCommand(java.lang.String, byte[], + * net.rubyeye.xmemcached.command.CommandType) + */ + @SuppressWarnings("unchecked") + public final Command createGetCommand(final String key, final byte[] keyBytes, + final CommandType cmdType, Transcoder transcoder) { + return new TextGetOneCommand(key, keyBytes, cmdType, new CountDownLatch(1)); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.CommandFactory#createGetMultiCommand(java.util .Collection, + * java.util.concurrent.CountDownLatch, net.rubyeye.xmemcached.command.CommandType, + * net.rubyeye.xmemcached.transcoders.Transcoder) + */ + public final Command createGetMultiCommand(Collection keys, CountDownLatch latch, + CommandType cmdType, Transcoder transcoder) { + StringBuilder sb = new StringBuilder(keys.size() * 5); + for (String tmpKey : keys) { + ByteUtils.checkKey(tmpKey); + sb.append(tmpKey).append(" "); + } + String gatherKey = sb.toString(); + byte[] keyBytes = ByteUtils.getBytes(gatherKey.substring(0, gatherKey.length() - 1)); + return new TextGetMultiCommand(keys.iterator().next(), keyBytes, cmdType, latch, transcoder); + } + + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.CommandFactory#createIncrDecrCommand(java.lang .String, byte[], + * int, net.rubyeye.xmemcached.command.CommandType) + */ + public final Command createIncrDecrCommand(final String key, final byte[] keyBytes, + final long amount, long initial, int exptime, CommandType cmdType, boolean noreply) { + return new TextIncrDecrCommand(key, keyBytes, cmdType, new CountDownLatch(1), amount, initial, + noreply); + } + + public Command createAuthListMechanismsCommand(CountDownLatch latch) { + throw new UnsupportedOperationException("SASL is only supported by binary protocol"); + } + + public Command createAuthStartCommand(String mechanism, CountDownLatch latch, byte[] authData) { + throw new UnsupportedOperationException("SASL is only supported by binary protocol"); + } + + public Command createAuthStepCommand(String mechanism, CountDownLatch latch, byte[] authData) { + throw new UnsupportedOperationException("SASL is only supported by binary protocol"); + } + + public Command createGetAndTouchCommand(String key, byte[] keyBytes, CountDownLatch latch, + int exp, boolean noreply) { + throw new UnsupportedOperationException("GAT is only supported by binary protocol"); + } + + public Command createTouchCommand(String key, byte[] keyBytes, CountDownLatch latch, int exp, + boolean noreply) { + return new TextTouchCommand(key, keyBytes, CommandType.TOUCH, latch, exp, noreply); + } + + public Command createQuitCommand() { + return new TextQuitCommand(); + } + + public Protocol getProtocol() { + return Protocol.Text; + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/VerbosityCommand.java b/src/main/java/net/rubyeye/xmemcached/command/VerbosityCommand.java index 6ade2390d..ac753b645 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/VerbosityCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/VerbosityCommand.java @@ -10,21 +10,21 @@ */ public abstract class VerbosityCommand extends Command { - protected int level; + protected int level; - public final int getLevel() { - return level; - } + public final int getLevel() { + return level; + } - public final void setLevel(int logLevel) { - this.level = logLevel; - } + public final void setLevel(int logLevel) { + this.level = logLevel; + } - public VerbosityCommand(CountDownLatch latch, int level, boolean noreply) { - super(CommandType.VERBOSITY, latch); - this.level = level; - this.key = "[verbosity]"; - this.noreply = noreply; - } + public VerbosityCommand(CountDownLatch latch, int level, boolean noreply) { + super(CommandType.VERBOSITY, latch); + this.level = level; + this.key = "[verbosity]"; + this.noreply = noreply; + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BaseBinaryCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BaseBinaryCommand.java index c76e1096a..424c312d9 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BaseBinaryCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BaseBinaryCommand.java @@ -1,30 +1,23 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.binary; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.Command; import net.rubyeye.xmemcached.command.CommandType; import net.rubyeye.xmemcached.command.StoreCommand; @@ -36,7 +29,6 @@ import net.rubyeye.xmemcached.transcoders.Transcoder; import net.rubyeye.xmemcached.utils.ByteUtils; import net.rubyeye.xmemcached.utils.OpaqueGenerater; - import com.google.code.yanf4j.buffer.IoBuffer; /** @@ -45,386 +37,372 @@ * @author dennis * */ -public abstract class BaseBinaryCommand extends Command - implements - StoreCommand { - static final short DEFAULT_VBUCKET_ID = 0; - protected int expTime; - protected long cas; - protected Object value; - - protected OpCode opCode; - protected BinaryDecodeStatus decodeStatus = BinaryDecodeStatus.NONE; - protected int responseKeyLength, responseExtrasLength, - responseTotalBodyLength; - protected ResponseStatus responseStatus; - protected int opaque; - protected short vbucketId = DEFAULT_VBUCKET_ID; - - @SuppressWarnings("unchecked") - public BaseBinaryCommand(String key, byte[] keyBytes, CommandType cmdType, - CountDownLatch latch, int exp, long cas, Object value, - boolean noreply, Transcoder transcoder) { - super(key, keyBytes, cmdType, latch); - this.expTime = exp; - this.cas = cas; - this.value = value; - this.noreply = noreply; - this.transcoder = transcoder; - } - - public final int getExpTime() { - return this.expTime; - } - - public final void setExpTime(int exp) { - this.expTime = exp; - } - - public final long getCas() { - return this.cas; - } - - public int getOpaque() { - return this.opaque; - } - - public void setOpaque(int opaque) { - this.opaque = opaque; - } - - public final void setCas(long cas) { - this.cas = cas; - } - - public final Object getValue() { - return this.value; - } - - public final void setValue(Object value) { - this.value = value; - } - - @Override - @SuppressWarnings("unchecked") - public final Transcoder getTranscoder() { - return this.transcoder; - } - - @Override - @SuppressWarnings("unchecked") - public final void setTranscoder(Transcoder transcoder) { - this.transcoder = transcoder; - } - - @Override - public boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { - while (true) { - LABEL : switch (this.decodeStatus) { - case NONE : - if (buffer.remaining() < 24) { - return false; - } else { - this.decodeStatus = BinaryDecodeStatus.READ_HEADER; - } - continue; - case READ_HEADER : - this.readHeader(buffer); - continue; - case READ_EXTRAS : - if (this.readExtras(buffer, this.responseExtrasLength)) { - this.decodeStatus = BinaryDecodeStatus.READ_KEY; - continue; - } else { - return false; - } - case READ_KEY : - if (this.readKey(buffer, this.responseKeyLength)) { - this.decodeStatus = BinaryDecodeStatus.READ_VALUE; - continue; - } else { - return false; - } - case READ_VALUE : - if (this.responseStatus == null - || this.responseStatus == ResponseStatus.NO_ERROR) { - if (this.readValue(buffer, this.responseTotalBodyLength, - this.responseKeyLength, - this.responseExtrasLength)) { - this.decodeStatus = BinaryDecodeStatus.DONE; - continue; - } else { - return false; - } - } else { - // Ignore error message - if (ByteUtils.stepBuffer(buffer, - this.responseTotalBodyLength - - this.responseKeyLength - - this.responseExtrasLength)) { - this.decodeStatus = BinaryDecodeStatus.DONE; - continue; - } else { - return false; - } - } - case DONE : - if (this.finish()) { - return true; - } else { - // Do not finish,continue to decode - this.decodeStatus = BinaryDecodeStatus.NONE; - break LABEL; - } - case IGNORE : - buffer.reset(); - return true; - } - } - } - - protected boolean finish() { - if (this.result == null) { - if (this.responseStatus == ResponseStatus.NO_ERROR) { - this.setResult(Boolean.TRUE); - } else { - this.setResult(Boolean.FALSE); - } - } - this.countDownLatch(); - return true; - } - - protected void readHeader(ByteBuffer buffer) { - this.markBuffer(buffer); - this.readMagicNumber(buffer); - if (!this.readOpCode(buffer)) { - this.decodeStatus = BinaryDecodeStatus.IGNORE; - return; - } - this.readKeyLength(buffer); - this.readExtrasLength(buffer); - this.readDataType(buffer); - this.readStatus(buffer); - this.readBodyLength(buffer); - if (!this.readOpaque(buffer)) { - this.decodeStatus = BinaryDecodeStatus.IGNORE; - return; - } - this.decodeStatus = BinaryDecodeStatus.READ_EXTRAS; - this.readCAS(buffer); - - } - - private void markBuffer(ByteBuffer buffer) { - buffer.mark(); - } - - protected boolean readOpaque(ByteBuffer buffer) { - if (this.noreply) { - int returnOpaque = buffer.getInt(); - if (returnOpaque != this.opaque) { - return false; - } - } else { - ByteUtils.stepBuffer(buffer, 4); - } - return true; - } - - protected long readCAS(ByteBuffer buffer) { - ByteUtils.stepBuffer(buffer, 8); - return 0; - } - - protected boolean readKey(ByteBuffer buffer, int keyLength) { - return ByteUtils.stepBuffer(buffer, keyLength); - } - - protected boolean readValue(ByteBuffer buffer, int bodyLength, - int keyLength, int extrasLength) { - return ByteUtils.stepBuffer(buffer, - bodyLength - keyLength - extrasLength); - } - - protected boolean readExtras(ByteBuffer buffer, int extrasLength) { - return ByteUtils.stepBuffer(buffer, extrasLength); - } - - private int readBodyLength(ByteBuffer buffer) { - this.responseTotalBodyLength = buffer.getInt(); - return this.responseTotalBodyLength; - } - - protected void readStatus(ByteBuffer buffer) { - this.responseStatus = ResponseStatus.parseShort(buffer.getShort()); - switch (this.responseStatus) { - case NOT_SUPPORTED : - case UNKNOWN_COMMAND : - this.setException(new UnknownCommandException()); - break; - case AUTH_REQUIRED : - case FUTHER_AUTH_REQUIRED : - case VALUE_TOO_BIG : - case INVALID_ARGUMENTS : - case INC_DEC_NON_NUM : - case BELONGS_TO_ANOTHER_SRV : - case AUTH_ERROR : - case OUT_OF_MEMORY : - case INTERNAL_ERROR : - case BUSY : - case TEMP_FAILURE : - this.setException(new MemcachedServerException( - this.responseStatus.errorMessage())); - break; - } - - } - - public final OpCode getOpCode() { - return this.opCode; - } - - public final void setOpCode(OpCode opCode) { - this.opCode = opCode; - } - - public final ResponseStatus getResponseStatus() { - return this.responseStatus; - } - - public final void setResponseStatus(ResponseStatus responseStatus) { - this.responseStatus = responseStatus; - } - - private int readKeyLength(ByteBuffer buffer) { - this.responseKeyLength = buffer.getShort(); - return this.responseKeyLength; - } - - private int readExtrasLength(ByteBuffer buffer) { - this.responseExtrasLength = buffer.get(); - return this.responseExtrasLength; - } - - private byte readDataType(ByteBuffer buffer) { - return buffer.get(); - } - - protected boolean readOpCode(ByteBuffer buffer) { - byte op = buffer.get(); - if (op != this.opCode.fieldValue()) { - if (this.noreply) { - return false; - } else { - throw new MemcachedDecodeException( - "Not a proper " + this.opCode.name() + " response"); - } - } - return true; - } - - private void readMagicNumber(ByteBuffer buffer) { - byte magic = buffer.get(); - - if (magic != RESPONSE_MAGIC_NUMBER) { - throw new MemcachedDecodeException("Not a proper response"); - } - } - - /** - * Set,add,replace protocol's extras length - */ - static final byte EXTRAS_LENGTH = (byte) 8; - - @Override - @SuppressWarnings("unchecked") - public void encode() { - CachedData data = null; - if (this.transcoder != null) { - data = this.transcoder.encode(this.value); - } - // header+key+value+extras - int length = 24 + this.getKeyLength() + this.getValueLength(data) - + this.getExtrasLength(); - - this.ioBuffer = IoBuffer.allocate(length); - this.fillHeader(data); - this.fillExtras(data); - this.fillKey(); - this.fillValue(data); - - this.ioBuffer.flip(); - - } - - protected void fillValue(final CachedData data) { - this.ioBuffer.put(data.getData()); - } - - protected void fillKey() { - this.ioBuffer.put(this.keyBytes); - } - - protected void fillExtras(final CachedData data) { - this.ioBuffer.putInt(data.getFlag()); - this.ioBuffer.putInt(this.expTime); - } - - private void fillHeader(final CachedData data) { - byte[] bs = new byte[24]; - bs[0] = REQUEST_MAGIC_NUMBER; - bs[1] = this.opCode.fieldValue(); - short keyLen = getKeyLength(); - bs[2] = ByteUtils.short1(keyLen); - bs[3] = ByteUtils.short0(keyLen); - bs[4] = this.getExtrasLength(); - // dataType,always zero bs[5]=0; - - bs[6] = ByteUtils.short1(this.vbucketId); - bs[7] = ByteUtils.short0(this.vbucketId); - // body len - int bodyLen = this.getExtrasLength() + this.getKeyLength() - + this.getValueLength(data); - bs[8] = ByteUtils.int3(bodyLen); - bs[9] = ByteUtils.int2(bodyLen); - bs[10] = ByteUtils.int1(bodyLen); - bs[11] = ByteUtils.int0(bodyLen); - // Opaque - if (this.noreply) { - this.opaque = OpaqueGenerater.getInstance().getNextValue(); - } - bs[12] = ByteUtils.int3(this.opaque); - bs[13] = ByteUtils.int2(this.opaque); - bs[14] = ByteUtils.int1(this.opaque); - bs[15] = ByteUtils.int0(this.opaque); - // cas - long casValue = getCasValue(); - bs[16] = ByteUtils.long7(casValue); - bs[17] = ByteUtils.long6(casValue); - bs[18] = ByteUtils.long5(casValue); - bs[19] = ByteUtils.long4(casValue); - bs[20] = ByteUtils.long3(casValue); - bs[21] = ByteUtils.long2(casValue); - bs[22] = ByteUtils.long1(casValue); - bs[23] = ByteUtils.long0(casValue); - this.ioBuffer.put(bs); - } - - protected long getCasValue() { - return 0L; - } - - protected int getValueLength(final CachedData data) { - return data.getData().length; - } - - protected short getKeyLength() { - return (short) this.keyBytes.length; - } - - protected byte getExtrasLength() { - return EXTRAS_LENGTH; - } +public abstract class BaseBinaryCommand extends Command implements StoreCommand { + static final short DEFAULT_VBUCKET_ID = 0; + protected int expTime; + protected long cas; + protected Object value; + + protected OpCode opCode; + protected BinaryDecodeStatus decodeStatus = BinaryDecodeStatus.NONE; + protected int responseKeyLength, responseExtrasLength, responseTotalBodyLength; + protected ResponseStatus responseStatus; + protected int opaque; + protected short vbucketId = DEFAULT_VBUCKET_ID; + + @SuppressWarnings("unchecked") + public BaseBinaryCommand(String key, byte[] keyBytes, CommandType cmdType, CountDownLatch latch, + int exp, long cas, Object value, boolean noreply, Transcoder transcoder) { + super(key, keyBytes, cmdType, latch); + this.expTime = exp; + this.cas = cas; + this.value = value; + this.noreply = noreply; + this.transcoder = transcoder; + } + + public final int getExpTime() { + return this.expTime; + } + + public final void setExpTime(int exp) { + this.expTime = exp; + } + + public final long getCas() { + return this.cas; + } + + public int getOpaque() { + return this.opaque; + } + + public void setOpaque(int opaque) { + this.opaque = opaque; + } + + public final void setCas(long cas) { + this.cas = cas; + } + + public final Object getValue() { + return this.value; + } + + public final void setValue(Object value) { + this.value = value; + } + + @Override + @SuppressWarnings("unchecked") + public final Transcoder getTranscoder() { + return this.transcoder; + } + + @Override + @SuppressWarnings("unchecked") + public final void setTranscoder(Transcoder transcoder) { + this.transcoder = transcoder; + } + + @Override + public boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { + while (true) { + LABEL: switch (this.decodeStatus) { + case NONE: + if (buffer.remaining() < 24) { + return false; + } else { + this.decodeStatus = BinaryDecodeStatus.READ_HEADER; + } + continue; + case READ_HEADER: + this.readHeader(buffer); + continue; + case READ_EXTRAS: + if (this.readExtras(buffer, this.responseExtrasLength)) { + this.decodeStatus = BinaryDecodeStatus.READ_KEY; + continue; + } else { + return false; + } + case READ_KEY: + if (this.readKey(buffer, this.responseKeyLength)) { + this.decodeStatus = BinaryDecodeStatus.READ_VALUE; + continue; + } else { + return false; + } + case READ_VALUE: + if (this.responseStatus == null || this.responseStatus == ResponseStatus.NO_ERROR) { + if (this.readValue(buffer, this.responseTotalBodyLength, this.responseKeyLength, + this.responseExtrasLength)) { + this.decodeStatus = BinaryDecodeStatus.DONE; + continue; + } else { + return false; + } + } else { + // Ignore error message + if (ByteUtils.stepBuffer(buffer, this.responseTotalBodyLength - this.responseKeyLength + - this.responseExtrasLength)) { + this.decodeStatus = BinaryDecodeStatus.DONE; + continue; + } else { + return false; + } + } + case DONE: + if (this.finish()) { + return true; + } else { + // Do not finish,continue to decode + this.decodeStatus = BinaryDecodeStatus.NONE; + break LABEL; + } + case IGNORE: + buffer.reset(); + return true; + } + } + } + + protected boolean finish() { + if (this.result == null) { + if (this.responseStatus == ResponseStatus.NO_ERROR) { + this.setResult(Boolean.TRUE); + } else { + this.setResult(Boolean.FALSE); + } + } + this.countDownLatch(); + return true; + } + + protected void readHeader(ByteBuffer buffer) { + this.markBuffer(buffer); + this.readMagicNumber(buffer); + if (!this.readOpCode(buffer)) { + this.decodeStatus = BinaryDecodeStatus.IGNORE; + return; + } + this.readKeyLength(buffer); + this.readExtrasLength(buffer); + this.readDataType(buffer); + this.readStatus(buffer); + this.readBodyLength(buffer); + if (!this.readOpaque(buffer)) { + this.decodeStatus = BinaryDecodeStatus.IGNORE; + return; + } + this.decodeStatus = BinaryDecodeStatus.READ_EXTRAS; + this.readCAS(buffer); + + } + + private void markBuffer(ByteBuffer buffer) { + buffer.mark(); + } + + protected boolean readOpaque(ByteBuffer buffer) { + if (this.noreply) { + int returnOpaque = buffer.getInt(); + if (returnOpaque != this.opaque) { + return false; + } + } else { + ByteUtils.stepBuffer(buffer, 4); + } + return true; + } + + protected long readCAS(ByteBuffer buffer) { + ByteUtils.stepBuffer(buffer, 8); + return 0; + } + + protected boolean readKey(ByteBuffer buffer, int keyLength) { + return ByteUtils.stepBuffer(buffer, keyLength); + } + + protected boolean readValue(ByteBuffer buffer, int bodyLength, int keyLength, int extrasLength) { + return ByteUtils.stepBuffer(buffer, bodyLength - keyLength - extrasLength); + } + + protected boolean readExtras(ByteBuffer buffer, int extrasLength) { + return ByteUtils.stepBuffer(buffer, extrasLength); + } + + private int readBodyLength(ByteBuffer buffer) { + this.responseTotalBodyLength = buffer.getInt(); + return this.responseTotalBodyLength; + } + + protected void readStatus(ByteBuffer buffer) { + this.responseStatus = ResponseStatus.parseShort(buffer.getShort()); + switch (this.responseStatus) { + case NOT_SUPPORTED: + case UNKNOWN_COMMAND: + this.setException(new UnknownCommandException()); + break; + case AUTH_REQUIRED: + case FUTHER_AUTH_REQUIRED: + case VALUE_TOO_BIG: + case INVALID_ARGUMENTS: + case INC_DEC_NON_NUM: + case BELONGS_TO_ANOTHER_SRV: + case AUTH_ERROR: + case OUT_OF_MEMORY: + case INTERNAL_ERROR: + case BUSY: + case TEMP_FAILURE: + this.setException(new MemcachedServerException(this.responseStatus.errorMessage())); + break; + } + + } + + public final OpCode getOpCode() { + return this.opCode; + } + + public final void setOpCode(OpCode opCode) { + this.opCode = opCode; + } + + public final ResponseStatus getResponseStatus() { + return this.responseStatus; + } + + public final void setResponseStatus(ResponseStatus responseStatus) { + this.responseStatus = responseStatus; + } + + private int readKeyLength(ByteBuffer buffer) { + this.responseKeyLength = buffer.getShort(); + return this.responseKeyLength; + } + + private int readExtrasLength(ByteBuffer buffer) { + this.responseExtrasLength = buffer.get(); + return this.responseExtrasLength; + } + + private byte readDataType(ByteBuffer buffer) { + return buffer.get(); + } + + protected boolean readOpCode(ByteBuffer buffer) { + byte op = buffer.get(); + if (op != this.opCode.fieldValue()) { + if (this.noreply) { + return false; + } else { + throw new MemcachedDecodeException("Not a proper " + this.opCode.name() + " response"); + } + } + return true; + } + + private void readMagicNumber(ByteBuffer buffer) { + byte magic = buffer.get(); + + if (magic != RESPONSE_MAGIC_NUMBER) { + throw new MemcachedDecodeException("Not a proper response"); + } + } + + /** + * Set,add,replace protocol's extras length + */ + static final byte EXTRAS_LENGTH = (byte) 8; + + @Override + @SuppressWarnings("unchecked") + public void encode() { + CachedData data = null; + if (this.transcoder != null) { + data = this.transcoder.encode(this.value); + } + // header+key+value+extras + int length = 24 + this.getKeyLength() + this.getValueLength(data) + this.getExtrasLength(); + + this.ioBuffer = IoBuffer.allocate(length); + this.fillHeader(data); + this.fillExtras(data); + this.fillKey(); + this.fillValue(data); + + this.ioBuffer.flip(); + + } + + protected void fillValue(final CachedData data) { + this.ioBuffer.put(data.getData()); + } + + protected void fillKey() { + this.ioBuffer.put(this.keyBytes); + } + + protected void fillExtras(final CachedData data) { + this.ioBuffer.putInt(data.getFlag()); + this.ioBuffer.putInt(this.expTime); + } + + private void fillHeader(final CachedData data) { + byte[] bs = new byte[24]; + bs[0] = REQUEST_MAGIC_NUMBER; + bs[1] = this.opCode.fieldValue(); + short keyLen = getKeyLength(); + bs[2] = ByteUtils.short1(keyLen); + bs[3] = ByteUtils.short0(keyLen); + bs[4] = this.getExtrasLength(); + // dataType,always zero bs[5]=0; + + bs[6] = ByteUtils.short1(this.vbucketId); + bs[7] = ByteUtils.short0(this.vbucketId); + // body len + int bodyLen = this.getExtrasLength() + this.getKeyLength() + this.getValueLength(data); + bs[8] = ByteUtils.int3(bodyLen); + bs[9] = ByteUtils.int2(bodyLen); + bs[10] = ByteUtils.int1(bodyLen); + bs[11] = ByteUtils.int0(bodyLen); + // Opaque + if (this.noreply) { + this.opaque = OpaqueGenerater.getInstance().getNextValue(); + } + bs[12] = ByteUtils.int3(this.opaque); + bs[13] = ByteUtils.int2(this.opaque); + bs[14] = ByteUtils.int1(this.opaque); + bs[15] = ByteUtils.int0(this.opaque); + // cas + long casValue = getCasValue(); + bs[16] = ByteUtils.long7(casValue); + bs[17] = ByteUtils.long6(casValue); + bs[18] = ByteUtils.long5(casValue); + bs[19] = ByteUtils.long4(casValue); + bs[20] = ByteUtils.long3(casValue); + bs[21] = ByteUtils.long2(casValue); + bs[22] = ByteUtils.long1(casValue); + bs[23] = ByteUtils.long0(casValue); + this.ioBuffer.put(bs); + } + + protected long getCasValue() { + return 0L; + } + + protected int getValueLength(final CachedData data) { + return data.getData().length; + } + + protected short getKeyLength() { + return (short) this.keyBytes.length; + } + + protected byte getExtrasLength() { + return EXTRAS_LENGTH; + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAWSElasticCacheConfigCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAWSElasticCacheConfigCommand.java index 9b9e9c61c..a3b0aa1e9 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAWSElasticCacheConfigCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAWSElasticCacheConfigCommand.java @@ -1,30 +1,23 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.binary; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.CommandType; import net.rubyeye.xmemcached.transcoders.CachedData; import net.rubyeye.xmemcached.utils.ByteUtils; @@ -33,56 +26,54 @@ * AWS ElasticCache config command * * @author dennis - * + * */ public class BinaryAWSElasticCacheConfigCommand extends BaseBinaryCommand { - public BinaryAWSElasticCacheConfigCommand(final CountDownLatch latch, - String subCommand, String key) { - super(key, ByteUtils.getBytes(key), CommandType.AWS_CONFIG, latch, 0, 0, - latch, false, null); - this.commandType = CommandType.AWS_CONFIG; - if (subCommand.equals("get")) { - this.opCode = OpCode.CONFIG_GET; - } else if (subCommand.equals("set")) { - this.opCode = OpCode.CONFIG_SET; - } else if (subCommand.equals("delete")) { - this.opCode = OpCode.CONFIG_DEL; - } - } + public BinaryAWSElasticCacheConfigCommand(final CountDownLatch latch, String subCommand, + String key) { + super(key, ByteUtils.getBytes(key), CommandType.AWS_CONFIG, latch, 0, 0, latch, false, null); + this.commandType = CommandType.AWS_CONFIG; + if (subCommand.equals("get")) { + this.opCode = OpCode.CONFIG_GET; + } else if (subCommand.equals("set")) { + this.opCode = OpCode.CONFIG_SET; + } else if (subCommand.equals("delete")) { + this.opCode = OpCode.CONFIG_DEL; + } + } - @Override - protected boolean readValue(ByteBuffer buffer, int bodyLength, - int keyLength, int extrasLength) { - int valueLength = bodyLength - keyLength - extrasLength; - if (buffer.remaining() < valueLength) { - return false; - } - byte[] bytes = new byte[valueLength]; - buffer.get(bytes); - setResult(new String(bytes)); - countDownLatch(); - return true; - } + @Override + protected boolean readValue(ByteBuffer buffer, int bodyLength, int keyLength, int extrasLength) { + int valueLength = bodyLength - keyLength - extrasLength; + if (buffer.remaining() < valueLength) { + return false; + } + byte[] bytes = new byte[valueLength]; + buffer.get(bytes); + setResult(new String(bytes)); + countDownLatch(); + return true; + } - @Override - protected void fillExtras(CachedData data) { - // must not have extras - } + @Override + protected void fillExtras(CachedData data) { + // must not have extras + } - @Override - protected void fillValue(CachedData data) { - // must not have value - } + @Override + protected void fillValue(CachedData data) { + // must not have value + } - @Override - protected byte getExtrasLength() { - return 0; - } + @Override + protected byte getExtrasLength() { + return 0; + } - @Override - protected int getValueLength(CachedData data) { - return 0; - } + @Override + protected int getValueLength(CachedData data) { + return 0; + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAppendPrependCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAppendPrependCommand.java index 9d1758682..c19ed096b 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAppendPrependCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAppendPrependCommand.java @@ -1,29 +1,22 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.binary; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.CommandType; import net.rubyeye.xmemcached.exception.UnknownCommandException; import net.rubyeye.xmemcached.transcoders.CachedData; @@ -38,32 +31,30 @@ @SuppressWarnings("unchecked") public class BinaryAppendPrependCommand extends BaseBinaryCommand { - public BinaryAppendPrependCommand(String key, byte[] keyBytes, - CommandType cmdType, CountDownLatch latch, int exp, long cas, - Object value, boolean noreply, Transcoder transcoder) { - super(key, keyBytes, cmdType, latch, exp, cas, value, noreply, - transcoder); - switch (cmdType) { - case APPEND : - this.opCode = noreply ? OpCode.APPEND_QUIETLY : OpCode.APPEND; - break; - case PREPEND : - this.opCode = noreply ? OpCode.PREPEND_QUIETLY : OpCode.PREPEND; - break; - default : - throw new UnknownCommandException( - "Not a append or prepend command:" + cmdType.name()); - } - } + public BinaryAppendPrependCommand(String key, byte[] keyBytes, CommandType cmdType, + CountDownLatch latch, int exp, long cas, Object value, boolean noreply, + Transcoder transcoder) { + super(key, keyBytes, cmdType, latch, exp, cas, value, noreply, transcoder); + switch (cmdType) { + case APPEND: + this.opCode = noreply ? OpCode.APPEND_QUIETLY : OpCode.APPEND; + break; + case PREPEND: + this.opCode = noreply ? OpCode.PREPEND_QUIETLY : OpCode.PREPEND; + break; + default: + throw new UnknownCommandException("Not a append or prepend command:" + cmdType.name()); + } + } - @Override - protected void fillExtras(CachedData data) { - // no extras - } + @Override + protected void fillExtras(CachedData data) { + // no extras + } - @Override - protected byte getExtrasLength() { - return 0; - } + @Override + protected byte getExtrasLength() { + return 0; + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAuthListMechanismsCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAuthListMechanismsCommand.java index 049bf3659..dbce03e8d 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAuthListMechanismsCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAuthListMechanismsCommand.java @@ -1,66 +1,63 @@ -package net.rubyeye.xmemcached.command.binary; - -import java.nio.ByteBuffer; -import java.util.concurrent.CountDownLatch; - -import net.rubyeye.xmemcached.command.CommandType; -import net.rubyeye.xmemcached.transcoders.CachedData; - -/** - * List auth mechanisms command - * - * @author dennis - * - */ -public class BinaryAuthListMechanismsCommand extends BaseBinaryCommand { - - public BinaryAuthListMechanismsCommand(CountDownLatch latch) { - super(null, null, CommandType.AUTH_LIST, latch, 0, 0, null, false, - null); - this.opCode = OpCode.AUTH_LIST_MECHANISMS; - } - - @Override - protected boolean readValue(ByteBuffer buffer, int bodyLength, - int keyLength, int extrasLength) { - int valueLength = bodyLength - keyLength - extrasLength; - if (buffer.remaining() < valueLength) { - return false; - } - byte[] bytes = new byte[valueLength]; - buffer.get(bytes); - setResult(new String(bytes)); - countDownLatch(); - return true; - } - - @Override - protected void fillExtras(CachedData data) { - // must not have extras - } - - @Override - protected void fillValue(CachedData data) { - // must not have value - } - - @Override - protected byte getExtrasLength() { - return 0; - } - - @Override - protected void fillKey() { - // must not have key - } - - @Override - protected short getKeyLength() { - return 0; - } - - @Override - protected int getValueLength(CachedData data) { - return 0; - } -} +package net.rubyeye.xmemcached.command.binary; + +import java.nio.ByteBuffer; +import java.util.concurrent.CountDownLatch; +import net.rubyeye.xmemcached.command.CommandType; +import net.rubyeye.xmemcached.transcoders.CachedData; + +/** + * List auth mechanisms command + * + * @author dennis + * + */ +public class BinaryAuthListMechanismsCommand extends BaseBinaryCommand { + + public BinaryAuthListMechanismsCommand(CountDownLatch latch) { + super(null, null, CommandType.AUTH_LIST, latch, 0, 0, null, false, null); + this.opCode = OpCode.AUTH_LIST_MECHANISMS; + } + + @Override + protected boolean readValue(ByteBuffer buffer, int bodyLength, int keyLength, int extrasLength) { + int valueLength = bodyLength - keyLength - extrasLength; + if (buffer.remaining() < valueLength) { + return false; + } + byte[] bytes = new byte[valueLength]; + buffer.get(bytes); + setResult(new String(bytes)); + countDownLatch(); + return true; + } + + @Override + protected void fillExtras(CachedData data) { + // must not have extras + } + + @Override + protected void fillValue(CachedData data) { + // must not have value + } + + @Override + protected byte getExtrasLength() { + return 0; + } + + @Override + protected void fillKey() { + // must not have key + } + + @Override + protected short getKeyLength() { + return 0; + } + + @Override + protected int getValueLength(CachedData data) { + return 0; + } +} diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAuthStartCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAuthStartCommand.java index 7a3dcd1cb..3489765af 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAuthStartCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAuthStartCommand.java @@ -1,63 +1,60 @@ -package net.rubyeye.xmemcached.command.binary; - -import java.nio.ByteBuffer; -import java.util.concurrent.CountDownLatch; - -import net.rubyeye.xmemcached.command.CommandType; -import net.rubyeye.xmemcached.transcoders.CachedData; - -/** - * Auth start command - * - * @author dennis - * - */ -public class BinaryAuthStartCommand extends BaseBinaryCommand { - - public BinaryAuthStartCommand(String mechanism, byte[] keyBytes, - CountDownLatch latch, byte[] authData) { - super(mechanism, keyBytes, CommandType.AUTH_START, latch, 0, 0, - authData, false, null); - this.opCode = OpCode.AUTH_START; - - } - - @Override - protected void fillExtras(CachedData data) { - // must not have extras - } - - @Override - protected void fillValue(CachedData data) { - if (this.value != null) - this.ioBuffer.put((byte[]) this.value); - } - - @Override - protected int getValueLength(CachedData data) { - if (this.value == null) - return 0; - else - return ((byte[]) this.value).length; - } - - @Override - protected byte getExtrasLength() { - return (byte) 0; - } - - @Override - protected boolean readValue(ByteBuffer buffer, int bodyLength, - int keyLength, int extrasLength) { - int valueLength = bodyLength - keyLength - extrasLength; - if (buffer.remaining() < valueLength) { - return false; - } - byte[] bytes = new byte[valueLength]; - buffer.get(bytes); - setResult(new String(bytes)); - countDownLatch(); - return true; - } - -} +package net.rubyeye.xmemcached.command.binary; + +import java.nio.ByteBuffer; +import java.util.concurrent.CountDownLatch; +import net.rubyeye.xmemcached.command.CommandType; +import net.rubyeye.xmemcached.transcoders.CachedData; + +/** + * Auth start command + * + * @author dennis + * + */ +public class BinaryAuthStartCommand extends BaseBinaryCommand { + + public BinaryAuthStartCommand(String mechanism, byte[] keyBytes, CountDownLatch latch, + byte[] authData) { + super(mechanism, keyBytes, CommandType.AUTH_START, latch, 0, 0, authData, false, null); + this.opCode = OpCode.AUTH_START; + + } + + @Override + protected void fillExtras(CachedData data) { + // must not have extras + } + + @Override + protected void fillValue(CachedData data) { + if (this.value != null) + this.ioBuffer.put((byte[]) this.value); + } + + @Override + protected int getValueLength(CachedData data) { + if (this.value == null) + return 0; + else + return ((byte[]) this.value).length; + } + + @Override + protected byte getExtrasLength() { + return (byte) 0; + } + + @Override + protected boolean readValue(ByteBuffer buffer, int bodyLength, int keyLength, int extrasLength) { + int valueLength = bodyLength - keyLength - extrasLength; + if (buffer.remaining() < valueLength) { + return false; + } + byte[] bytes = new byte[valueLength]; + buffer.get(bytes); + setResult(new String(bytes)); + countDownLatch(); + return true; + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAuthStepCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAuthStepCommand.java index cfc1d38e9..be0051661 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAuthStepCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryAuthStepCommand.java @@ -1,62 +1,59 @@ -package net.rubyeye.xmemcached.command.binary; - -import java.nio.ByteBuffer; -import java.util.concurrent.CountDownLatch; - -import net.rubyeye.xmemcached.command.CommandType; -import net.rubyeye.xmemcached.transcoders.CachedData; - -/** - * Auth step command - * - * @author dennis - * - */ -public class BinaryAuthStepCommand extends BaseBinaryCommand { - - public BinaryAuthStepCommand(String mechanism, byte[] keyBytes, - CountDownLatch latch, byte[] authData) { - super(mechanism, keyBytes, CommandType.AUTH_STEP, latch, 0, 0, authData, - false, null); - this.opCode = OpCode.AUTH_STEP; - } - - @Override - protected void fillExtras(CachedData data) { - // must not have extras - } - - @Override - protected void fillValue(CachedData data) { - if (this.value != null) - this.ioBuffer.put((byte[]) this.value); - } - - @Override - protected int getValueLength(CachedData data) { - if (this.value == null) - return 0; - else - return ((byte[]) this.value).length; - } - - @Override - protected byte getExtrasLength() { - return (byte) 0; - } - - @Override - protected boolean readValue(ByteBuffer buffer, int bodyLength, - int keyLength, int extrasLength) { - int valueLength = bodyLength - keyLength - extrasLength; - if (buffer.remaining() < valueLength) { - return false; - } - byte[] bytes = new byte[valueLength]; - buffer.get(bytes); - setResult(new String(bytes)); - countDownLatch(); - return true; - } - -} +package net.rubyeye.xmemcached.command.binary; + +import java.nio.ByteBuffer; +import java.util.concurrent.CountDownLatch; +import net.rubyeye.xmemcached.command.CommandType; +import net.rubyeye.xmemcached.transcoders.CachedData; + +/** + * Auth step command + * + * @author dennis + * + */ +public class BinaryAuthStepCommand extends BaseBinaryCommand { + + public BinaryAuthStepCommand(String mechanism, byte[] keyBytes, CountDownLatch latch, + byte[] authData) { + super(mechanism, keyBytes, CommandType.AUTH_STEP, latch, 0, 0, authData, false, null); + this.opCode = OpCode.AUTH_STEP; + } + + @Override + protected void fillExtras(CachedData data) { + // must not have extras + } + + @Override + protected void fillValue(CachedData data) { + if (this.value != null) + this.ioBuffer.put((byte[]) this.value); + } + + @Override + protected int getValueLength(CachedData data) { + if (this.value == null) + return 0; + else + return ((byte[]) this.value).length; + } + + @Override + protected byte getExtrasLength() { + return (byte) 0; + } + + @Override + protected boolean readValue(ByteBuffer buffer, int bodyLength, int keyLength, int extrasLength) { + int valueLength = bodyLength - keyLength - extrasLength; + if (buffer.remaining() < valueLength) { + return false; + } + byte[] bytes = new byte[valueLength]; + buffer.get(bytes); + setResult(new String(bytes)); + countDownLatch(); + return true; + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryCASCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryCASCommand.java index 0a7f74efb..16aa6b3a0 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryCASCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryCASCommand.java @@ -1,29 +1,22 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.binary; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.CommandType; import net.rubyeye.xmemcached.transcoders.Transcoder; @@ -36,24 +29,22 @@ @SuppressWarnings("unchecked") public class BinaryCASCommand extends BaseBinaryCommand { - public BinaryCASCommand(String key, byte[] keyBytes, CommandType cmdType, - CountDownLatch latch, int exp, long cas, Object value, - boolean noreply, Transcoder transcoder) { - super(key, keyBytes, cmdType, latch, exp, cas, value, noreply, - transcoder); - switch (cmdType) { - case CAS : - this.opCode = noreply ? OpCode.SET_QUIETLY : OpCode.SET; - break; - default : - throw new IllegalArgumentException( - "Unknow cas command type:" + cmdType); - } + public BinaryCASCommand(String key, byte[] keyBytes, CommandType cmdType, CountDownLatch latch, + int exp, long cas, Object value, boolean noreply, Transcoder transcoder) { + super(key, keyBytes, cmdType, latch, exp, cas, value, noreply, transcoder); + switch (cmdType) { + case CAS: + this.opCode = noreply ? OpCode.SET_QUIETLY : OpCode.SET; + break; + default: + throw new IllegalArgumentException("Unknow cas command type:" + cmdType); + } + + } - } - @Override - protected long getCasValue() { - return this.cas; - } + @Override + protected long getCasValue() { + return this.cas; + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryDecodeStatus.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryDecodeStatus.java index 1a6cd9ad2..e6593c4ea 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryDecodeStatus.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryDecodeStatus.java @@ -1,32 +1,27 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.binary; + /** * Binary protocol decode status. * * @author dennis - * + * */ public enum BinaryDecodeStatus { - NONE, READ_HEADER, READ_EXTRAS, READ_KEY, READ_VALUE, DONE, IGNORE + NONE, READ_HEADER, READ_EXTRAS, READ_KEY, READ_VALUE, DONE, IGNORE } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryDeleteCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryDeleteCommand.java index c8aa1b7f3..bc31521f1 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryDeleteCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryDeleteCommand.java @@ -1,85 +1,79 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.binary; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.CommandType; import net.rubyeye.xmemcached.transcoders.CachedData; + /** * Binary delete command * * @author boyan - * + * */ public class BinaryDeleteCommand extends BaseBinaryCommand { - public BinaryDeleteCommand(String key, byte[] keyBytes, long cas, - CommandType cmdType, CountDownLatch latch, boolean noreply) { - super(key, keyBytes, cmdType, latch, 0, cas, null, noreply, null); - this.opCode = noreply ? OpCode.DELETE_QUIETLY : OpCode.DELETE; - } + public BinaryDeleteCommand(String key, byte[] keyBytes, long cas, CommandType cmdType, + CountDownLatch latch, boolean noreply) { + super(key, keyBytes, cmdType, latch, 0, cas, null, noreply, null); + this.opCode = noreply ? OpCode.DELETE_QUIETLY : OpCode.DELETE; + } - /** - * optimistic,if no error,goto done - */ - @Override - protected void readHeader(ByteBuffer buffer) { - super.readHeader(buffer); - if (this.responseStatus == ResponseStatus.NO_ERROR) { - this.decodeStatus = BinaryDecodeStatus.DONE; - } + /** + * optimistic,if no error,goto done + */ + @Override + protected void readHeader(ByteBuffer buffer) { + super.readHeader(buffer); + if (this.responseStatus == ResponseStatus.NO_ERROR) { + this.decodeStatus = BinaryDecodeStatus.DONE; + } - } + } - @Override - protected long getCasValue() { - if (this.cas > 0) { - return this.cas; - } else { - return super.getCasValue(); - } - } + @Override + protected long getCasValue() { + if (this.cas > 0) { + return this.cas; + } else { + return super.getCasValue(); + } + } - @Override - protected void fillExtras(CachedData data) { - // must not have extras - } + @Override + protected void fillExtras(CachedData data) { + // must not have extras + } - @Override - protected byte getExtrasLength() { - return 0; - } + @Override + protected byte getExtrasLength() { + return 0; + } - @Override - protected int getValueLength(CachedData data) { - return 0; - } + @Override + protected int getValueLength(CachedData data) { + return 0; + } - @Override - protected void fillValue(CachedData data) { - // must not have value - } + @Override + protected void fillValue(CachedData data) { + // must not have value + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryFlushAllCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryFlushAllCommand.java index 41d32357a..6c693b2d1 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryFlushAllCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryFlushAllCommand.java @@ -1,83 +1,75 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.binary; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.CommandType; import net.rubyeye.xmemcached.transcoders.CachedData; + /** * Flush command for binary protocol * * @author dennis - * + * */ public class BinaryFlushAllCommand extends BaseBinaryCommand { - private int exptime; + private int exptime; - public BinaryFlushAllCommand(CountDownLatch latch, int exptime, - boolean noreply) { - super("[flush_all]", null, CommandType.FLUSH_ALL, latch, 0, 0, null, - noreply, null); - this.opCode = noreply ? OpCode.FLUSH_QUIETLY : OpCode.FLUSH; - this.expTime = exptime; - } + public BinaryFlushAllCommand(CountDownLatch latch, int exptime, boolean noreply) { + super("[flush_all]", null, CommandType.FLUSH_ALL, latch, 0, 0, null, noreply, null); + this.opCode = noreply ? OpCode.FLUSH_QUIETLY : OpCode.FLUSH; + this.expTime = exptime; + } - @Override - protected void fillExtras(CachedData data) { - if (this.expTime > 0) { - this.ioBuffer.putInt(this.expTime); - } - } + @Override + protected void fillExtras(CachedData data) { + if (this.expTime > 0) { + this.ioBuffer.putInt(this.expTime); + } + } - @Override - protected byte getExtrasLength() { - if (this.exptime > 0) { - return 4; - } else { - return 0; - } - } + @Override + protected byte getExtrasLength() { + if (this.exptime > 0) { + return 4; + } else { + return 0; + } + } - @Override - protected short getKeyLength() { - return 0; - } + @Override + protected short getKeyLength() { + return 0; + } - @Override - protected int getValueLength(CachedData data) { - return 0; - } + @Override + protected int getValueLength(CachedData data) { + return 0; + } - @Override - protected void fillKey() { - // must not have key - } + @Override + protected void fillKey() { + // must not have key + } - @Override - protected void fillValue(CachedData data) { - // must not have value - } + @Override + protected void fillValue(CachedData data) { + // must not have value + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryGetAndTouchCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryGetAndTouchCommand.java index fa9b5a60c..f1c11ba81 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryGetAndTouchCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryGetAndTouchCommand.java @@ -1,44 +1,41 @@ -package net.rubyeye.xmemcached.command.binary; - -import java.util.concurrent.CountDownLatch; - -import net.rubyeye.xmemcached.command.CommandType; -import net.rubyeye.xmemcached.transcoders.CachedData; - -/** - * Binary GAT/GATQ command - * - * @author dennis - * - */ -public class BinaryGetAndTouchCommand extends BinaryGetCommand { - - public BinaryGetAndTouchCommand(String key, byte[] keyBytes, - CommandType cmdType, CountDownLatch latch, int exp, - boolean noreply) { - super(key, keyBytes, cmdType, latch, null, noreply); - this.expTime = exp; - switch (cmdType) { - case GAT : - this.opCode = OpCode.GAT; - break; - case GATQ : - this.opCode = OpCode.GATQ; - break; - default : - throw new IllegalArgumentException( - "Invalid GAT command type:" + cmdType); - } - } - - @Override - protected void fillExtras(CachedData data) { - this.ioBuffer.putInt(this.expTime); - } - - @Override - protected byte getExtrasLength() { - return 4; - } - -} +package net.rubyeye.xmemcached.command.binary; + +import java.util.concurrent.CountDownLatch; +import net.rubyeye.xmemcached.command.CommandType; +import net.rubyeye.xmemcached.transcoders.CachedData; + +/** + * Binary GAT/GATQ command + * + * @author dennis + * + */ +public class BinaryGetAndTouchCommand extends BinaryGetCommand { + + public BinaryGetAndTouchCommand(String key, byte[] keyBytes, CommandType cmdType, + CountDownLatch latch, int exp, boolean noreply) { + super(key, keyBytes, cmdType, latch, null, noreply); + this.expTime = exp; + switch (cmdType) { + case GAT: + this.opCode = OpCode.GAT; + break; + case GATQ: + this.opCode = OpCode.GATQ; + break; + default: + throw new IllegalArgumentException("Invalid GAT command type:" + cmdType); + } + } + + @Override + protected void fillExtras(CachedData data) { + this.ioBuffer.putInt(this.expTime); + } + + @Override + protected byte getExtrasLength() { + return 4; + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryGetCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryGetCommand.java index 43a8ac3fb..3832881ce 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryGetCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryGetCommand.java @@ -1,31 +1,24 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.binary; import java.nio.ByteBuffer; import java.util.List; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.AssocCommandAware; import net.rubyeye.xmemcached.command.Command; import net.rubyeye.xmemcached.command.CommandType; @@ -38,135 +31,128 @@ * @author dennis * */ -public class BinaryGetCommand extends BaseBinaryCommand - implements - AssocCommandAware { - private String responseKey; - private CachedData responseValue; - private List assocCommands; - - public final String getResponseKey() { - return this.responseKey; - } - - public final void setResponseKey(String responseKey) { - this.responseKey = responseKey; - } - - public BinaryGetCommand(String key, byte[] keyBytes, CommandType cmdType, - CountDownLatch latch, OpCode opCode, boolean noreply) { - super(key, keyBytes, cmdType, latch, 0, 0, null, noreply, null); - this.opCode = opCode; - this.responseValue = new CachedData(); - } - - public final List getAssocCommands() { - return this.assocCommands; - } - - public final void setAssocCommands(List assocCommands) { - this.assocCommands = assocCommands; - } - - /** - * Optimistic,if the value length is 0,then skip remaining buffer,set result - * as null - */ - protected void readHeader(ByteBuffer buffer) { - super.readHeader(buffer); - if (this.responseStatus != ResponseStatus.NO_ERROR) { - if (ByteUtils.stepBuffer(buffer, this.responseTotalBodyLength)) { - this.decodeStatus = BinaryDecodeStatus.DONE; - } - } - - } - - @Override - protected boolean finish() { - countDownLatch(); - return true; - } - - @Override - protected boolean readKey(ByteBuffer buffer, int keyLength) { - if (buffer.remaining() < keyLength) { - return false; - } - if (keyLength > 0) { - byte[] bytes = new byte[keyLength]; - buffer.get(bytes); - this.responseKey = ByteUtils.getString(bytes); - } - return true; - } - - @Override - protected boolean readValue(ByteBuffer buffer, int bodyLength, - int keyLength, int extrasLength) { - if (this.responseStatus == ResponseStatus.NO_ERROR) { - int valueLength = bodyLength - keyLength - extrasLength; - if (valueLength >= 0 && this.responseValue.getCapacity() < 0) { - this.responseValue.setCapacity(valueLength); - this.responseValue.setData(new byte[valueLength]); - } - int remainingCapacity = this.responseValue.remainingCapacity(); - int remaining = buffer.remaining(); - if (remaining < remainingCapacity) { - int length = remaining > remainingCapacity - ? remainingCapacity - : remaining; - this.responseValue.fillData(buffer, length); - return false; - } else if (remainingCapacity > 0) { - this.responseValue.fillData(buffer, remainingCapacity); - } - setResult(this.responseValue); - return true; - } else { - return ByteUtils.stepBuffer(buffer, - bodyLength - keyLength - extrasLength); - } - } - - @Override - protected boolean readExtras(ByteBuffer buffer, int extrasLength) { - if (buffer.remaining() < extrasLength) { - return false; - } - if (extrasLength > 0) { - // read flag - int flag = buffer.getInt(); - this.responseValue.setFlag(flag); - } - return true; - } - - @Override - protected void fillExtras(CachedData data) { - // must not have extras - } - - @Override - protected void fillValue(CachedData data) { - // must not have value - } - - @Override - protected byte getExtrasLength() { - return 0; - } - - @Override - protected int getValueLength(CachedData data) { - return 0; - } - - @Override - protected long readCAS(ByteBuffer buffer) { - long cas = buffer.getLong(); - this.responseValue.setCas(cas); - return cas; - } +public class BinaryGetCommand extends BaseBinaryCommand implements AssocCommandAware { + private String responseKey; + private CachedData responseValue; + private List assocCommands; + + public final String getResponseKey() { + return this.responseKey; + } + + public final void setResponseKey(String responseKey) { + this.responseKey = responseKey; + } + + public BinaryGetCommand(String key, byte[] keyBytes, CommandType cmdType, CountDownLatch latch, + OpCode opCode, boolean noreply) { + super(key, keyBytes, cmdType, latch, 0, 0, null, noreply, null); + this.opCode = opCode; + this.responseValue = new CachedData(); + } + + public final List getAssocCommands() { + return this.assocCommands; + } + + public final void setAssocCommands(List assocCommands) { + this.assocCommands = assocCommands; + } + + /** + * Optimistic,if the value length is 0,then skip remaining buffer,set result as null + */ + protected void readHeader(ByteBuffer buffer) { + super.readHeader(buffer); + if (this.responseStatus != ResponseStatus.NO_ERROR) { + if (ByteUtils.stepBuffer(buffer, this.responseTotalBodyLength)) { + this.decodeStatus = BinaryDecodeStatus.DONE; + } + } + + } + + @Override + protected boolean finish() { + countDownLatch(); + return true; + } + + @Override + protected boolean readKey(ByteBuffer buffer, int keyLength) { + if (buffer.remaining() < keyLength) { + return false; + } + if (keyLength > 0) { + byte[] bytes = new byte[keyLength]; + buffer.get(bytes); + this.responseKey = ByteUtils.getString(bytes); + } + return true; + } + + @Override + protected boolean readValue(ByteBuffer buffer, int bodyLength, int keyLength, int extrasLength) { + if (this.responseStatus == ResponseStatus.NO_ERROR) { + int valueLength = bodyLength - keyLength - extrasLength; + if (valueLength >= 0 && this.responseValue.getCapacity() < 0) { + this.responseValue.setCapacity(valueLength); + this.responseValue.setData(new byte[valueLength]); + } + int remainingCapacity = this.responseValue.remainingCapacity(); + int remaining = buffer.remaining(); + if (remaining < remainingCapacity) { + int length = remaining > remainingCapacity ? remainingCapacity : remaining; + this.responseValue.fillData(buffer, length); + return false; + } else if (remainingCapacity > 0) { + this.responseValue.fillData(buffer, remainingCapacity); + } + setResult(this.responseValue); + return true; + } else { + return ByteUtils.stepBuffer(buffer, bodyLength - keyLength - extrasLength); + } + } + + @Override + protected boolean readExtras(ByteBuffer buffer, int extrasLength) { + if (buffer.remaining() < extrasLength) { + return false; + } + if (extrasLength > 0) { + // read flag + int flag = buffer.getInt(); + this.responseValue.setFlag(flag); + } + return true; + } + + @Override + protected void fillExtras(CachedData data) { + // must not have extras + } + + @Override + protected void fillValue(CachedData data) { + // must not have value + } + + @Override + protected byte getExtrasLength() { + return 0; + } + + @Override + protected int getValueLength(CachedData data) { + return 0; + } + + @Override + protected long readCAS(ByteBuffer buffer) { + long cas = buffer.getLong(); + this.responseValue.setCas(cas); + return cas; + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryGetMultiCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryGetMultiCommand.java index 41ac4e4b2..c9bd7e872 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryGetMultiCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryGetMultiCommand.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.binary; @@ -27,7 +21,6 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.Command; import net.rubyeye.xmemcached.command.CommandType; import net.rubyeye.xmemcached.command.MapReturnValueAware; @@ -43,169 +36,158 @@ */ @SuppressWarnings("unchecked") public class BinaryGetMultiCommand extends BaseBinaryCommand - implements - MergeCommandsAware, - MapReturnValueAware { - private boolean finished; - private String responseKey; - private long responseCAS; - private int responseFlag; - private Map mergeCommands; - - public BinaryGetMultiCommand(String key, CommandType cmdType, - CountDownLatch latch) { - super(key, null, cmdType, latch, 0, 0, null, false, null); - this.result = new HashMap(); - } - - public Map getReturnValues() { - return (Map) this.result; - } - - @Override - protected boolean readOpCode(ByteBuffer buffer) { - byte opCode = buffer.get(); - // last response is GET_KEY,then finish decoding - if (opCode == OpCode.GET_KEY.fieldValue()) { - this.finished = true; - } - return true; - } - - /** - * optimistic,if response status is greater than zero,then skip buffer to - * next response,set result as null - */ - protected void readHeader(ByteBuffer buffer) { - super.readHeader(buffer); - if (this.responseStatus != ResponseStatus.NO_ERROR) { - if (ByteUtils.stepBuffer(buffer, this.responseTotalBodyLength)) { - this.decodeStatus = BinaryDecodeStatus.DONE; - } - } - } - - @Override - public void encode() { - // do nothing - } - - @Override - protected boolean finish() { - final CachedData cachedData = ((Map) this.result) - .get(this.responseKey); - Map mergetCommands = getMergeCommands(); - if (mergetCommands != null) { - final BinaryGetCommand command = (BinaryGetCommand) mergetCommands - .remove(this.responseKey); - if (command != null) { - command.setResult(cachedData); - command.countDownLatch(); - this.mergeCount--; - if (command.getAssocCommands() != null) { - for (Command assocCommand : command.getAssocCommands()) { - assocCommand.setResult(cachedData); - assocCommand.countDownLatch(); - this.mergeCount--; - } - } - - } - } - if (this.finished) { - if (getMergeCommands() != null) { - Collection mergeCommands = getMergeCommands().values(); - getIoBuffer().free(); - for (Command nextCommand : mergeCommands) { - BinaryGetCommand command = (BinaryGetCommand) nextCommand; - command.countDownLatch(); - if (command.getAssocCommands() != null) { - for (Command assocCommand : command - .getAssocCommands()) { - assocCommand.countDownLatch(); - } - } - } - } - countDownLatch(); - } else { - - this.responseKey = null; - } - return this.finished; - } - - @Override - protected boolean readKey(ByteBuffer buffer, int keyLength) { - if (buffer.remaining() < keyLength) { - return false; - } - if (keyLength > 0) { - byte[] bytes = new byte[keyLength]; - buffer.get(bytes); - this.responseKey = ByteUtils.getString(bytes); - CachedData value = new CachedData(); - value.setCas(this.responseCAS); - value.setFlag(this.responseFlag); - ((Map) this.result).put(this.responseKey, - value); - } - return true; - } - - @Override - protected boolean readValue(ByteBuffer buffer, int bodyLength, - int keyLength, int extrasLength) { - if (this.responseStatus == ResponseStatus.NO_ERROR) { - int valueLength = bodyLength - keyLength - extrasLength; - CachedData responseValue = ((Map) this.result) - .get(this.responseKey); - if (valueLength >= 0 && responseValue.getCapacity() < 0) { - responseValue.setCapacity(valueLength); - responseValue.setData(new byte[valueLength]); - } - int remainingCapacity = responseValue.remainingCapacity(); - int remaining = buffer.remaining(); - if (remaining < remainingCapacity) { - int length = remaining > remainingCapacity - ? remainingCapacity - : remaining; - responseValue.fillData(buffer, length); - return false; - } else if (remainingCapacity > 0) { - responseValue.fillData(buffer, remainingCapacity); - } - return true; - } else { - ((Map) this.result).remove(this.responseKey); - return true; - } - } - - @Override - protected boolean readExtras(ByteBuffer buffer, int extrasLength) { - if (buffer.remaining() < extrasLength) { - return false; - } - if (extrasLength == 4) { - // read flag - this.responseFlag = buffer.getInt(); - } - return true; - } - - @Override - protected long readCAS(ByteBuffer buffer) { - this.responseCAS = buffer.getLong(); - return this.responseCAS; - } - - public Map getMergeCommands() { - return this.mergeCommands; - } - - public void setMergeCommands(Map mergeCommands) { - this.mergeCommands = mergeCommands; - } + implements MergeCommandsAware, MapReturnValueAware { + private boolean finished; + private String responseKey; + private long responseCAS; + private int responseFlag; + private Map mergeCommands; + + public BinaryGetMultiCommand(String key, CommandType cmdType, CountDownLatch latch) { + super(key, null, cmdType, latch, 0, 0, null, false, null); + this.result = new HashMap(); + } + + public Map getReturnValues() { + return (Map) this.result; + } + + @Override + protected boolean readOpCode(ByteBuffer buffer) { + byte opCode = buffer.get(); + // last response is GET_KEY,then finish decoding + if (opCode == OpCode.GET_KEY.fieldValue()) { + this.finished = true; + } + return true; + } + + /** + * optimistic,if response status is greater than zero,then skip buffer to next response,set result + * as null + */ + protected void readHeader(ByteBuffer buffer) { + super.readHeader(buffer); + if (this.responseStatus != ResponseStatus.NO_ERROR) { + if (ByteUtils.stepBuffer(buffer, this.responseTotalBodyLength)) { + this.decodeStatus = BinaryDecodeStatus.DONE; + } + } + } + + @Override + public void encode() { + // do nothing + } + + @Override + protected boolean finish() { + final CachedData cachedData = ((Map) this.result).get(this.responseKey); + Map mergetCommands = getMergeCommands(); + if (mergetCommands != null) { + final BinaryGetCommand command = (BinaryGetCommand) mergetCommands.remove(this.responseKey); + if (command != null) { + command.setResult(cachedData); + command.countDownLatch(); + this.mergeCount--; + if (command.getAssocCommands() != null) { + for (Command assocCommand : command.getAssocCommands()) { + assocCommand.setResult(cachedData); + assocCommand.countDownLatch(); + this.mergeCount--; + } + } + + } + } + if (this.finished) { + if (getMergeCommands() != null) { + Collection mergeCommands = getMergeCommands().values(); + getIoBuffer().free(); + for (Command nextCommand : mergeCommands) { + BinaryGetCommand command = (BinaryGetCommand) nextCommand; + command.countDownLatch(); + if (command.getAssocCommands() != null) { + for (Command assocCommand : command.getAssocCommands()) { + assocCommand.countDownLatch(); + } + } + } + } + countDownLatch(); + } else { + + this.responseKey = null; + } + return this.finished; + } + + @Override + protected boolean readKey(ByteBuffer buffer, int keyLength) { + if (buffer.remaining() < keyLength) { + return false; + } + if (keyLength > 0) { + byte[] bytes = new byte[keyLength]; + buffer.get(bytes); + this.responseKey = ByteUtils.getString(bytes); + CachedData value = new CachedData(); + value.setCas(this.responseCAS); + value.setFlag(this.responseFlag); + ((Map) this.result).put(this.responseKey, value); + } + return true; + } + + @Override + protected boolean readValue(ByteBuffer buffer, int bodyLength, int keyLength, int extrasLength) { + if (this.responseStatus == ResponseStatus.NO_ERROR) { + int valueLength = bodyLength - keyLength - extrasLength; + CachedData responseValue = ((Map) this.result).get(this.responseKey); + if (valueLength >= 0 && responseValue.getCapacity() < 0) { + responseValue.setCapacity(valueLength); + responseValue.setData(new byte[valueLength]); + } + int remainingCapacity = responseValue.remainingCapacity(); + int remaining = buffer.remaining(); + if (remaining < remainingCapacity) { + int length = remaining > remainingCapacity ? remainingCapacity : remaining; + responseValue.fillData(buffer, length); + return false; + } else if (remainingCapacity > 0) { + responseValue.fillData(buffer, remainingCapacity); + } + return true; + } else { + ((Map) this.result).remove(this.responseKey); + return true; + } + } + + @Override + protected boolean readExtras(ByteBuffer buffer, int extrasLength) { + if (buffer.remaining() < extrasLength) { + return false; + } + if (extrasLength == 4) { + // read flag + this.responseFlag = buffer.getInt(); + } + return true; + } + + @Override + protected long readCAS(ByteBuffer buffer) { + this.responseCAS = buffer.getLong(); + return this.responseCAS; + } + + public Map getMergeCommands() { + return this.mergeCommands; + } + + public void setMergeCommands(Map mergeCommands) { + this.mergeCommands = mergeCommands; + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryIncrDecrCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryIncrDecrCommand.java index c6758cd6d..57f7ef7a5 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryIncrDecrCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryIncrDecrCommand.java @@ -1,114 +1,101 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.binary; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.CommandType; import net.rubyeye.xmemcached.transcoders.CachedData; + /** * Binary incr/decr command * * @author dennis - * + * */ public class BinaryIncrDecrCommand extends BaseBinaryCommand { - private long amount, initial; + private long amount, initial; - public final long getAmount() { - return this.amount; - } + public final long getAmount() { + return this.amount; + } - public final void setAmount(long amount) { - this.amount = amount; - } + public final void setAmount(long amount) { + this.amount = amount; + } - public final long getInitial() { - return this.initial; - } + public final long getInitial() { + return this.initial; + } - public final void setInitial(long initial) { - this.initial = initial; - } + public final void setInitial(long initial) { + this.initial = initial; + } - public BinaryIncrDecrCommand(String key, byte[] keyBytes, long amount, - long initial, int expTime, CommandType cmdType, boolean noreply) { - super(key, keyBytes, cmdType, new CountDownLatch(1), 0, 0, null, - noreply, null); - this.amount = amount; - this.initial = initial; - this.expTime = expTime; - switch (cmdType) { - case INCR : - this.opCode = noreply - ? OpCode.INCREMENT_QUIETLY - : OpCode.INCREMENT; - break; - case DECR : - this.opCode = noreply - ? OpCode.DECREMENT_QUIETLY - : OpCode.DECREMENT; - break; - default : - throw new IllegalArgumentException( - "Unknow cmd type for incr/decr:" + cmdType); - } + public BinaryIncrDecrCommand(String key, byte[] keyBytes, long amount, long initial, int expTime, + CommandType cmdType, boolean noreply) { + super(key, keyBytes, cmdType, new CountDownLatch(1), 0, 0, null, noreply, null); + this.amount = amount; + this.initial = initial; + this.expTime = expTime; + switch (cmdType) { + case INCR: + this.opCode = noreply ? OpCode.INCREMENT_QUIETLY : OpCode.INCREMENT; + break; + case DECR: + this.opCode = noreply ? OpCode.DECREMENT_QUIETLY : OpCode.DECREMENT; + break; + default: + throw new IllegalArgumentException("Unknow cmd type for incr/decr:" + cmdType); + } - } + } - @Override - protected void fillExtras(CachedData data) { - this.ioBuffer.putLong(this.amount); - this.ioBuffer.putLong(this.initial); - this.ioBuffer.putInt(this.expTime); - } + @Override + protected void fillExtras(CachedData data) { + this.ioBuffer.putLong(this.amount); + this.ioBuffer.putLong(this.initial); + this.ioBuffer.putInt(this.expTime); + } - @Override - protected byte getExtrasLength() { - return 20; - } + @Override + protected byte getExtrasLength() { + return 20; + } - @Override - protected void fillValue(CachedData data) { - // must not have value - } + @Override + protected void fillValue(CachedData data) { + // must not have value + } - @Override - protected int getValueLength(CachedData data) { - return 0; - } + @Override + protected int getValueLength(CachedData data) { + return 0; + } - @Override - protected boolean readValue(ByteBuffer buffer, int bodyLength, - int keyLength, int extrasLength) { - if (buffer.remaining() < 8) { - return false; - } - long returnValue = buffer.getLong(); - setResult(returnValue); - return true; - } + @Override + protected boolean readValue(ByteBuffer buffer, int bodyLength, int keyLength, int extrasLength) { + if (buffer.remaining() < 8) { + return false; + } + long returnValue = buffer.getLong(); + setResult(returnValue); + return true; + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryNoopCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryNoopCommand.java index 15a127e78..863a7be5e 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryNoopCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryNoopCommand.java @@ -1,29 +1,22 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.binary; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.CommandType; /** @@ -34,9 +27,9 @@ */ public class BinaryNoopCommand extends BaseBinaryCommand { - public BinaryNoopCommand(CountDownLatch latch) { - super(null, null, CommandType.NOOP, latch, 0, 0, null, false, null); - this.opCode = OpCode.NOOP; - } + public BinaryNoopCommand(CountDownLatch latch) { + super(null, null, CommandType.NOOP, latch, 0, 0, null, false, null); + this.opCode = OpCode.NOOP; + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryQuitCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryQuitCommand.java index 2e7e251da..8cf528e53 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryQuitCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryQuitCommand.java @@ -1,82 +1,74 @@ -/** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 - */ -/** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 net.rubyeye.xmemcached.command.binary; - -import java.nio.ByteBuffer; - -import net.rubyeye.xmemcached.command.CommandType; -import net.rubyeye.xmemcached.impl.MemcachedTCPSession; -import net.rubyeye.xmemcached.transcoders.CachedData; - -/** - * Quit command for binary protocol - * - * @author boyan - * - */ -public class BinaryQuitCommand extends BaseBinaryCommand { - - public BinaryQuitCommand() { - super("version", null, CommandType.VERSION, null, 0, 0, null, false, - null); - commandType = CommandType.QUIT; - opCode = OpCode.QUITQ; - } - - @Override - public boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { - // ignore - return true; - } - - @Override - protected void fillExtras(CachedData data) { - // must not have extras - } - - @Override - protected void fillValue(CachedData data) { - // must not have value - } - - @Override - protected byte getExtrasLength() { - return 0; - } - - @Override - protected void fillKey() { - // must not have key - } - - @Override - protected short getKeyLength() { - return 0; - } - - @Override - protected int getValueLength(CachedData data) { - return 0; - } - -} +/** + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 + */ +/** + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.binary; + +import java.nio.ByteBuffer; +import net.rubyeye.xmemcached.command.CommandType; +import net.rubyeye.xmemcached.impl.MemcachedTCPSession; +import net.rubyeye.xmemcached.transcoders.CachedData; + +/** + * Quit command for binary protocol + * + * @author boyan + * + */ +public class BinaryQuitCommand extends BaseBinaryCommand { + + public BinaryQuitCommand() { + super("version", null, CommandType.VERSION, null, 0, 0, null, false, null); + commandType = CommandType.QUIT; + opCode = OpCode.QUITQ; + } + + @Override + public boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { + // ignore + return true; + } + + @Override + protected void fillExtras(CachedData data) { + // must not have extras + } + + @Override + protected void fillValue(CachedData data) { + // must not have value + } + + @Override + protected byte getExtrasLength() { + return 0; + } + + @Override + protected void fillKey() { + // must not have key + } + + @Override + protected short getKeyLength() { + return 0; + } + + @Override + protected int getValueLength(CachedData data) { + return 0; + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinarySetMultiCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinarySetMultiCommand.java index d2e7ac898..c6e805fe6 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinarySetMultiCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinarySetMultiCommand.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.binary; @@ -27,7 +21,6 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.Command; import net.rubyeye.xmemcached.command.CommandType; import net.rubyeye.xmemcached.command.MapReturnValueAware; @@ -42,106 +35,100 @@ * */ @SuppressWarnings("unchecked") -public class BinarySetMultiCommand extends BaseBinaryCommand - implements - MergeCommandsAware { - private boolean finished; - private Integer responseOpaque; - private Map mergeCommands; +public class BinarySetMultiCommand extends BaseBinaryCommand implements MergeCommandsAware { + private boolean finished; + private Integer responseOpaque; + private Map mergeCommands; - public BinarySetMultiCommand(String key, CommandType cmdType, - CountDownLatch latch) { - super(key, null, cmdType, latch, 0, 0, null, false, null); - this.result = new HashMap(); - } + public BinarySetMultiCommand(String key, CommandType cmdType, CountDownLatch latch) { + super(key, null, cmdType, latch, 0, 0, null, false, null); + this.result = new HashMap(); + } - @Override - protected boolean readOpCode(ByteBuffer buffer) { - byte opCode = buffer.get(); - // last response is SET,then finish decoding - if (opCode == OpCode.SET.fieldValue()) { - this.finished = true; - } - return true; - } + @Override + protected boolean readOpCode(ByteBuffer buffer) { + byte opCode = buffer.get(); + // last response is SET,then finish decoding + if (opCode == OpCode.SET.fieldValue()) { + this.finished = true; + } + return true; + } - /** - * optimistic,if response status is greater than zero,then skip buffer to - * next response,set result to be false. - */ - protected void readHeader(ByteBuffer buffer) { - super.readHeader(buffer); - if (this.responseStatus != ResponseStatus.NO_ERROR) { - if (ByteUtils.stepBuffer(buffer, this.responseTotalBodyLength)) { - this.decodeStatus = BinaryDecodeStatus.DONE; - } - } - } + /** + * optimistic,if response status is greater than zero,then skip buffer to next response,set result + * to be false. + */ + protected void readHeader(ByteBuffer buffer) { + super.readHeader(buffer); + if (this.responseStatus != ResponseStatus.NO_ERROR) { + if (ByteUtils.stepBuffer(buffer, this.responseTotalBodyLength)) { + this.decodeStatus = BinaryDecodeStatus.DONE; + } + } + } - public Map getMergeCommands() { - return mergeCommands; - } + public Map getMergeCommands() { + return mergeCommands; + } - public void setMergeCommands(Map mergeCommands) { - this.mergeCommands = mergeCommands; - } + public void setMergeCommands(Map mergeCommands) { + this.mergeCommands = mergeCommands; + } - @Override - public void encode() { - // do nothing - } + @Override + public void encode() { + // do nothing + } - @Override - protected boolean finish() { - final Boolean rt = ((Map) this.result) - .get(this.responseOpaque); - Map mergetCommands = getMergeCommands(); - if (mergetCommands != null) { - final BinaryStoreCommand command = (BinaryStoreCommand) mergetCommands - .remove(this.responseOpaque); - if (command != null) { - command.setResult(rt); - command.countDownLatch(); - this.mergeCount--; - } - } - if (this.finished) { - if (getMergeCommands() != null) { - Collection mergeCommands = getMergeCommands().values(); - getIoBuffer().free(); - for (Command nextCommand : mergeCommands) { - BinaryStoreCommand command = (BinaryStoreCommand) nextCommand; - // Default result is true,it's quiet. - command.setResult(Boolean.TRUE); - command.countDownLatch(); - this.mergeCount--; - } - } - assert (mergeCount == 0); - countDownLatch(); - } else { - this.responseOpaque = null; - } - return this.finished; - } + @Override + protected boolean finish() { + final Boolean rt = ((Map) this.result).get(this.responseOpaque); + Map mergetCommands = getMergeCommands(); + if (mergetCommands != null) { + final BinaryStoreCommand command = + (BinaryStoreCommand) mergetCommands.remove(this.responseOpaque); + if (command != null) { + command.setResult(rt); + command.countDownLatch(); + this.mergeCount--; + } + } + if (this.finished) { + if (getMergeCommands() != null) { + Collection mergeCommands = getMergeCommands().values(); + getIoBuffer().free(); + for (Command nextCommand : mergeCommands) { + BinaryStoreCommand command = (BinaryStoreCommand) nextCommand; + // Default result is true,it's quiet. + command.setResult(Boolean.TRUE); + command.countDownLatch(); + this.mergeCount--; + } + } + assert (mergeCount == 0); + countDownLatch(); + } else { + this.responseOpaque = null; + } + return this.finished; + } - protected boolean readOpaque(ByteBuffer buffer) { - responseOpaque = buffer.getInt(); + protected boolean readOpaque(ByteBuffer buffer) { + responseOpaque = buffer.getInt(); - Command cmd = this.getMergeCommands().get(responseOpaque); - if (cmd == null) { - // It's not this command's merged commands,we must ignore it. - return false; - } else { - if (this.responseStatus == ResponseStatus.NO_ERROR) { - ((Map) this.result).put(responseOpaque, - Boolean.TRUE); - } else { - ((Map) this.result).put(responseOpaque, - Boolean.FALSE); - } - return true; - } + Command cmd = this.getMergeCommands().get(responseOpaque); + if (cmd == null) { + // It's not this command's merged commands,we must ignore it. + return false; + } else { + if (this.responseStatus == ResponseStatus.NO_ERROR) { + ((Map) this.result).put(responseOpaque, Boolean.TRUE); + } else { + ((Map) this.result).put(responseOpaque, Boolean.FALSE); + } + return true; + } - } + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryStatsCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryStatsCommand.java index 0bca8300d..a3f9704d7 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryStatsCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryStatsCommand.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.binary; @@ -27,7 +21,6 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.CommandType; import net.rubyeye.xmemcached.command.ServerAddressAware; import net.rubyeye.xmemcached.exception.UnknownCommandException; @@ -38,128 +31,122 @@ * Stats command for binary protocol * * @author boyan - * + * */ -public class BinaryStatsCommand extends BaseBinaryCommand - implements - ServerAddressAware { - - private InetSocketAddress server; - private String itemName; - private String currentResponseItem; - - public String getItemName() { - return this.itemName; - } - - public final InetSocketAddress getServer() { - return this.server; - } - - public final void setServer(InetSocketAddress server) { - this.server = server; - } - - public void setItemName(String item) { - this.itemName = item; - } - - public BinaryStatsCommand(InetSocketAddress server, CountDownLatch latch, - String itemName) { - super(null, null, CommandType.STATS, latch, 0, 0, null, false, null); - this.server = server; - this.itemName = itemName; - this.opCode = OpCode.STAT; - this.result = new HashMap(); - } - - @Override - protected boolean finish() { - // last packet - if (this.currentResponseItem == null) { - return super.finish(); - } else { - // continue decode - this.currentResponseItem = null; - return false; - } - } - - @Override - protected void readStatus(ByteBuffer buffer) { - ResponseStatus responseStatus = ResponseStatus - .parseShort(buffer.getShort()); - if (responseStatus == ResponseStatus.UNKNOWN_COMMAND) { - setException(new UnknownCommandException()); - } - } - - @Override - protected boolean readKey(ByteBuffer buffer, int keyLength) { - if (buffer.remaining() < keyLength) { - return false; - } - if (keyLength > 0) { - byte[] bytes = new byte[keyLength]; - buffer.get(bytes); - this.currentResponseItem = new String(bytes); - } - return true; - } - - @Override - @SuppressWarnings("unchecked") - protected boolean readValue(ByteBuffer buffer, int bodyLength, - int keyLength, int extrasLength) { - int valueLength = bodyLength - keyLength - extrasLength; - if (buffer.remaining() < valueLength) { - return false; - } - if (valueLength > 0) { - byte[] bytes = new byte[valueLength]; - buffer.get(bytes); - String value = new String(bytes); - ((Map) this.result).put(this.currentResponseItem, - value); - } - return true; - } - - @Override - protected void fillExtras(CachedData data) { - // must not have extras - } - - @Override - protected void fillValue(CachedData data) { - // must not have value - } - - @Override - protected byte getExtrasLength() { - return 0; - } - - @Override - protected int getValueLength(CachedData data) { - return 0; - } - - @Override - protected void fillKey() { - if (this.itemName != null) { - byte[] keyBytes = ByteUtils.getBytes(this.itemName); - this.ioBuffer.put(keyBytes); - } - } - - @Override - protected short getKeyLength() { - if (this.itemName != null) { - return (short) this.itemName.length(); - } else { - return 0; - } - } +public class BinaryStatsCommand extends BaseBinaryCommand implements ServerAddressAware { + + private InetSocketAddress server; + private String itemName; + private String currentResponseItem; + + public String getItemName() { + return this.itemName; + } + + public final InetSocketAddress getServer() { + return this.server; + } + + public final void setServer(InetSocketAddress server) { + this.server = server; + } + + public void setItemName(String item) { + this.itemName = item; + } + + public BinaryStatsCommand(InetSocketAddress server, CountDownLatch latch, String itemName) { + super(null, null, CommandType.STATS, latch, 0, 0, null, false, null); + this.server = server; + this.itemName = itemName; + this.opCode = OpCode.STAT; + this.result = new HashMap(); + } + + @Override + protected boolean finish() { + // last packet + if (this.currentResponseItem == null) { + return super.finish(); + } else { + // continue decode + this.currentResponseItem = null; + return false; + } + } + + @Override + protected void readStatus(ByteBuffer buffer) { + ResponseStatus responseStatus = ResponseStatus.parseShort(buffer.getShort()); + if (responseStatus == ResponseStatus.UNKNOWN_COMMAND) { + setException(new UnknownCommandException()); + } + } + + @Override + protected boolean readKey(ByteBuffer buffer, int keyLength) { + if (buffer.remaining() < keyLength) { + return false; + } + if (keyLength > 0) { + byte[] bytes = new byte[keyLength]; + buffer.get(bytes); + this.currentResponseItem = new String(bytes); + } + return true; + } + + @Override + @SuppressWarnings("unchecked") + protected boolean readValue(ByteBuffer buffer, int bodyLength, int keyLength, int extrasLength) { + int valueLength = bodyLength - keyLength - extrasLength; + if (buffer.remaining() < valueLength) { + return false; + } + if (valueLength > 0) { + byte[] bytes = new byte[valueLength]; + buffer.get(bytes); + String value = new String(bytes); + ((Map) this.result).put(this.currentResponseItem, value); + } + return true; + } + + @Override + protected void fillExtras(CachedData data) { + // must not have extras + } + + @Override + protected void fillValue(CachedData data) { + // must not have value + } + + @Override + protected byte getExtrasLength() { + return 0; + } + + @Override + protected int getValueLength(CachedData data) { + return 0; + } + + @Override + protected void fillKey() { + if (this.itemName != null) { + byte[] keyBytes = ByteUtils.getBytes(this.itemName); + this.ioBuffer.put(keyBytes); + } + } + + @Override + protected short getKeyLength() { + if (this.itemName != null) { + return (short) this.itemName.length(); + } else { + return 0; + } + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryStoreCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryStoreCommand.java index 18d483736..bbef804b1 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryStoreCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryStoreCommand.java @@ -1,31 +1,24 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.binary; import java.nio.ByteBuffer; import java.util.List; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.AssocCommandAware; import net.rubyeye.xmemcached.command.Command; import net.rubyeye.xmemcached.command.CommandType; @@ -39,39 +32,36 @@ */ public class BinaryStoreCommand extends BaseBinaryCommand { - public BinaryStoreCommand(String key, byte[] keyBytes, CommandType cmdType, - CountDownLatch latch, int exp, long cas, Object value, - boolean noreply, Transcoder transcoder) { - super(key, keyBytes, cmdType, latch, exp, cas, value, noreply, - transcoder); - switch (cmdType) { - case SET : - this.opCode = noreply ? OpCode.SET_QUIETLY : OpCode.SET; - break; - case REPLACE : - this.opCode = noreply ? OpCode.REPLACE_QUIETLY : OpCode.REPLACE; - break; - case ADD : - this.opCode = noreply ? OpCode.ADD_QUIETLY : OpCode.ADD; - break; - case SET_MANY : - // ignore - break; - default : - throw new IllegalArgumentException( - "Unknow cmd type for storage commands:" + cmdType); + public BinaryStoreCommand(String key, byte[] keyBytes, CommandType cmdType, CountDownLatch latch, + int exp, long cas, Object value, boolean noreply, Transcoder transcoder) { + super(key, keyBytes, cmdType, latch, exp, cas, value, noreply, transcoder); + switch (cmdType) { + case SET: + this.opCode = noreply ? OpCode.SET_QUIETLY : OpCode.SET; + break; + case REPLACE: + this.opCode = noreply ? OpCode.REPLACE_QUIETLY : OpCode.REPLACE; + break; + case ADD: + this.opCode = noreply ? OpCode.ADD_QUIETLY : OpCode.ADD; + break; + case SET_MANY: + // ignore + break; + default: + throw new IllegalArgumentException("Unknow cmd type for storage commands:" + cmdType); - } - } + } + } - /** - * optimistic,if no error,goto done - */ - protected void readHeader(ByteBuffer buffer) { - super.readHeader(buffer); - if (this.responseStatus == ResponseStatus.NO_ERROR) { - this.decodeStatus = BinaryDecodeStatus.DONE; - } - } + /** + * optimistic,if no error,goto done + */ + protected void readHeader(ByteBuffer buffer) { + super.readHeader(buffer); + if (this.responseStatus == ResponseStatus.NO_ERROR) { + this.decodeStatus = BinaryDecodeStatus.DONE; + } + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryTouchCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryTouchCommand.java index 04e03c2d1..5747e244b 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryTouchCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryTouchCommand.java @@ -1,43 +1,42 @@ -package net.rubyeye.xmemcached.command.binary; - -import java.util.concurrent.CountDownLatch; - -import net.rubyeye.xmemcached.command.CommandType; -import net.rubyeye.xmemcached.transcoders.CachedData; - -/** - * Binary touch command - * - * @author dennis - * @since 1.3.3 - */ -public class BinaryTouchCommand extends BaseBinaryCommand { - - public BinaryTouchCommand(String key, byte[] keyBytes, CommandType cmdType, - CountDownLatch latch, int exp, boolean noreply) { - super(key, keyBytes, cmdType, latch, exp, 0, null, noreply, null); - this.opCode = OpCode.TOUCH; - - } - - @Override - protected void fillExtras(CachedData data) { - this.ioBuffer.putInt(this.expTime); - } - - @Override - protected void fillValue(CachedData data) { - // Must not have value - } - - @Override - protected byte getExtrasLength() { - return 4; - } - - @Override - protected int getValueLength(CachedData data) { - return 0; - } - -} +package net.rubyeye.xmemcached.command.binary; + +import java.util.concurrent.CountDownLatch; +import net.rubyeye.xmemcached.command.CommandType; +import net.rubyeye.xmemcached.transcoders.CachedData; + +/** + * Binary touch command + * + * @author dennis + * @since 1.3.3 + */ +public class BinaryTouchCommand extends BaseBinaryCommand { + + public BinaryTouchCommand(String key, byte[] keyBytes, CommandType cmdType, CountDownLatch latch, + int exp, boolean noreply) { + super(key, keyBytes, cmdType, latch, exp, 0, null, noreply, null); + this.opCode = OpCode.TOUCH; + + } + + @Override + protected void fillExtras(CachedData data) { + this.ioBuffer.putInt(this.expTime); + } + + @Override + protected void fillValue(CachedData data) { + // Must not have value + } + + @Override + protected byte getExtrasLength() { + return 4; + } + + @Override + protected int getValueLength(CachedData data) { + return 0; + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryVerbosityCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryVerbosityCommand.java index 049260139..ced8b276f 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryVerbosityCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryVerbosityCommand.java @@ -1,55 +1,52 @@ -package net.rubyeye.xmemcached.command.binary; - -import java.util.concurrent.CountDownLatch; - -import net.rubyeye.xmemcached.command.CommandType; -import net.rubyeye.xmemcached.transcoders.CachedData; - -/** - * Binary verbosity command - * - * @author dennis - * @since 1.3.3 - * - */ -public class BinaryVerbosityCommand extends BaseBinaryCommand { - - private int verbosity; - - public BinaryVerbosityCommand(CountDownLatch latch, int verbosity, - boolean noreply) { - super(null, null, CommandType.VERBOSITY, latch, 0, 0, null, noreply, - null); - this.opCode = OpCode.VERBOSITY; - } - - @Override - protected void fillExtras(CachedData data) { - this.ioBuffer.putInt(verbosity); - } - - protected void fillKey() { - // MUST NOT have key. - } - - @Override - protected byte getExtrasLength() { - // Total 4 bytes - return 4; - } - - @Override - protected short getKeyLength() { - return 0; - } - - @Override - protected int getValueLength(CachedData data) { - return 0; - } - - protected void fillValue(CachedData data) { - // MUST NOT have value. - } - -} +package net.rubyeye.xmemcached.command.binary; + +import java.util.concurrent.CountDownLatch; +import net.rubyeye.xmemcached.command.CommandType; +import net.rubyeye.xmemcached.transcoders.CachedData; + +/** + * Binary verbosity command + * + * @author dennis + * @since 1.3.3 + * + */ +public class BinaryVerbosityCommand extends BaseBinaryCommand { + + private int verbosity; + + public BinaryVerbosityCommand(CountDownLatch latch, int verbosity, boolean noreply) { + super(null, null, CommandType.VERBOSITY, latch, 0, 0, null, noreply, null); + this.opCode = OpCode.VERBOSITY; + } + + @Override + protected void fillExtras(CachedData data) { + this.ioBuffer.putInt(verbosity); + } + + protected void fillKey() { + // MUST NOT have key. + } + + @Override + protected byte getExtrasLength() { + // Total 4 bytes + return 4; + } + + @Override + protected short getKeyLength() { + return 0; + } + + @Override + protected int getValueLength(CachedData data) { + return 0; + } + + protected void fillValue(CachedData data) { + // MUST NOT have value. + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryVersionCommand.java b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryVersionCommand.java index 33bd82783..d71f1d89c 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryVersionCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/BinaryVersionCommand.java @@ -1,104 +1,93 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.binary; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.CommandType; import net.rubyeye.xmemcached.command.ServerAddressAware; import net.rubyeye.xmemcached.transcoders.CachedData; + /** * Version command for binary protocol * * @author boyan - * + * */ -public class BinaryVersionCommand extends BaseBinaryCommand - implements - ServerAddressAware { - public InetSocketAddress server; +public class BinaryVersionCommand extends BaseBinaryCommand implements ServerAddressAware { + public InetSocketAddress server; - public final InetSocketAddress getServer() { - return this.server; - } + public final InetSocketAddress getServer() { + return this.server; + } - public final void setServer(InetSocketAddress server) { - this.server = server; - } + public final void setServer(InetSocketAddress server) { + this.server = server; + } - public BinaryVersionCommand(final CountDownLatch latch, - InetSocketAddress server) { - super("[version]", null, CommandType.VERSION, latch, 0, 0, latch, false, - null); - this.commandType = CommandType.VERSION; - this.server = server; - this.opCode = OpCode.VERSION; - } + public BinaryVersionCommand(final CountDownLatch latch, InetSocketAddress server) { + super("[version]", null, CommandType.VERSION, latch, 0, 0, latch, false, null); + this.commandType = CommandType.VERSION; + this.server = server; + this.opCode = OpCode.VERSION; + } - @Override - protected boolean readValue(ByteBuffer buffer, int bodyLength, - int keyLength, int extrasLength) { - int valueLength = bodyLength - keyLength - extrasLength; - if (buffer.remaining() < valueLength) { - return false; - } - byte[] bytes = new byte[valueLength]; - buffer.get(bytes); - setResult(new String(bytes)); - countDownLatch(); - return true; - } + @Override + protected boolean readValue(ByteBuffer buffer, int bodyLength, int keyLength, int extrasLength) { + int valueLength = bodyLength - keyLength - extrasLength; + if (buffer.remaining() < valueLength) { + return false; + } + byte[] bytes = new byte[valueLength]; + buffer.get(bytes); + setResult(new String(bytes)); + countDownLatch(); + return true; + } - @Override - protected void fillExtras(CachedData data) { - // must not have extras - } + @Override + protected void fillExtras(CachedData data) { + // must not have extras + } - @Override - protected void fillValue(CachedData data) { - // must not have value - } + @Override + protected void fillValue(CachedData data) { + // must not have value + } - @Override - protected byte getExtrasLength() { - return 0; - } + @Override + protected byte getExtrasLength() { + return 0; + } - @Override - protected void fillKey() { - // must not have key - } + @Override + protected void fillKey() { + // must not have key + } - @Override - protected short getKeyLength() { - return 0; - } + @Override + protected short getKeyLength() { + return 0; + } - @Override - protected int getValueLength(CachedData data) { - return 0; - } + @Override + protected int getValueLength(CachedData data) { + return 0; + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/OpCode.java b/src/main/java/net/rubyeye/xmemcached/command/binary/OpCode.java index 9aa05e461..d7ef41134 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/OpCode.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/OpCode.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.binary; @@ -29,262 +23,262 @@ * */ public enum OpCode { - GET { - @Override - public byte fieldValue() { - return 0x00; - - } - }, - GET_QUIETLY { - @Override - public byte fieldValue() { - return 0x09; - - } - }, - GET_KEY { - @Override - public byte fieldValue() { - return 0x0C; - - } - }, - GET_KEY_QUIETLY { - @Override - public byte fieldValue() { - return 0x0D; - - } - }, - SET { - @Override - public byte fieldValue() { - return 0x01; - - } - }, - SET_QUIETLY { - @Override - public byte fieldValue() { - return 0x11; - - } - }, - REPLACE { - @Override - public byte fieldValue() { - return 0x03; - - } - }, - REPLACE_QUIETLY { - @Override - public byte fieldValue() { - return 0x13; - - } - }, - ADD { - @Override - public byte fieldValue() { - return 0x02; - - } - }, - ADD_QUIETLY { - @Override - public byte fieldValue() { - return 0x12; - - } - }, - APPEND { - @Override - public byte fieldValue() { - return 0x0E; - - } - }, - APPEND_QUIETLY { - @Override - public byte fieldValue() { - return 0x19; - - } - }, - PREPEND { - @Override - public byte fieldValue() { - return 0x0F; - - } - }, - PREPEND_QUIETLY { - @Override - public byte fieldValue() { - return 0x1A; - - } - }, - DELETE { - @Override - public byte fieldValue() { - return 0x04; - - } - }, - DELETE_QUIETLY { - @Override - public byte fieldValue() { - return 0x14; - - } - }, - VERSION { - @Override - public byte fieldValue() { - return 0x0b; - - } - }, - QUITQ { - @Override - public byte fieldValue() { - return 0x17; - - } - }, - STAT { - @Override - public byte fieldValue() { - return 0x10; - - } - }, - NOOP { - @Override - public byte fieldValue() { - return 0x0a; - - } - }, - INCREMENT { - @Override - public byte fieldValue() { - return 0x05; - - } - }, - INCREMENT_QUIETLY { - @Override - public byte fieldValue() { - return 0x15; - - } - }, - DECREMENT { - @Override - public byte fieldValue() { - return 0x06; - - } - }, - DECREMENT_QUIETLY { - @Override - public byte fieldValue() { - return 0x16; - - } - }, - FLUSH { - @Override - public byte fieldValue() { - return 0x08; - - } - }, - FLUSH_QUIETLY { - @Override - public byte fieldValue() { - return 0x18; - - } - }, - AUTH_LIST_MECHANISMS { - @Override - public byte fieldValue() { - return 0x20; - - } - }, - AUTH_START { - @Override - public byte fieldValue() { - return 0x21; - - } - }, - AUTH_STEP { - @Override - public byte fieldValue() { - return 0x22; - - } - }, - - VERBOSITY { - @Override - public byte fieldValue() { - return 0x1b; - - } - }, - - TOUCH { - @Override - public byte fieldValue() { - return 0x1c; - - } - }, - GAT { - @Override - public byte fieldValue() { - return 0x1d; - - } - }, - GATQ { - @Override - public byte fieldValue() { - return 0x1e; - - } - }, - // AWS ElasticCache config commands - // https://github.com/awslabs/aws-elasticache-cluster-client-memcached-for-java/commit/70bf7643963500db20749d97c071b64b954eabb3 - CONFIG_GET { - @Override - public byte fieldValue() { - return 0x60; - - } - }, - CONFIG_SET { - @Override - public byte fieldValue() { - return 0x64; - - } - }, - CONFIG_DEL { - @Override - public byte fieldValue() { - return 0x66; - - } - }; - - public abstract byte fieldValue(); + GET { + @Override + public byte fieldValue() { + return 0x00; + + } + }, + GET_QUIETLY { + @Override + public byte fieldValue() { + return 0x09; + + } + }, + GET_KEY { + @Override + public byte fieldValue() { + return 0x0C; + + } + }, + GET_KEY_QUIETLY { + @Override + public byte fieldValue() { + return 0x0D; + + } + }, + SET { + @Override + public byte fieldValue() { + return 0x01; + + } + }, + SET_QUIETLY { + @Override + public byte fieldValue() { + return 0x11; + + } + }, + REPLACE { + @Override + public byte fieldValue() { + return 0x03; + + } + }, + REPLACE_QUIETLY { + @Override + public byte fieldValue() { + return 0x13; + + } + }, + ADD { + @Override + public byte fieldValue() { + return 0x02; + + } + }, + ADD_QUIETLY { + @Override + public byte fieldValue() { + return 0x12; + + } + }, + APPEND { + @Override + public byte fieldValue() { + return 0x0E; + + } + }, + APPEND_QUIETLY { + @Override + public byte fieldValue() { + return 0x19; + + } + }, + PREPEND { + @Override + public byte fieldValue() { + return 0x0F; + + } + }, + PREPEND_QUIETLY { + @Override + public byte fieldValue() { + return 0x1A; + + } + }, + DELETE { + @Override + public byte fieldValue() { + return 0x04; + + } + }, + DELETE_QUIETLY { + @Override + public byte fieldValue() { + return 0x14; + + } + }, + VERSION { + @Override + public byte fieldValue() { + return 0x0b; + + } + }, + QUITQ { + @Override + public byte fieldValue() { + return 0x17; + + } + }, + STAT { + @Override + public byte fieldValue() { + return 0x10; + + } + }, + NOOP { + @Override + public byte fieldValue() { + return 0x0a; + + } + }, + INCREMENT { + @Override + public byte fieldValue() { + return 0x05; + + } + }, + INCREMENT_QUIETLY { + @Override + public byte fieldValue() { + return 0x15; + + } + }, + DECREMENT { + @Override + public byte fieldValue() { + return 0x06; + + } + }, + DECREMENT_QUIETLY { + @Override + public byte fieldValue() { + return 0x16; + + } + }, + FLUSH { + @Override + public byte fieldValue() { + return 0x08; + + } + }, + FLUSH_QUIETLY { + @Override + public byte fieldValue() { + return 0x18; + + } + }, + AUTH_LIST_MECHANISMS { + @Override + public byte fieldValue() { + return 0x20; + + } + }, + AUTH_START { + @Override + public byte fieldValue() { + return 0x21; + + } + }, + AUTH_STEP { + @Override + public byte fieldValue() { + return 0x22; + + } + }, + + VERBOSITY { + @Override + public byte fieldValue() { + return 0x1b; + + } + }, + + TOUCH { + @Override + public byte fieldValue() { + return 0x1c; + + } + }, + GAT { + @Override + public byte fieldValue() { + return 0x1d; + + } + }, + GATQ { + @Override + public byte fieldValue() { + return 0x1e; + + } + }, + // AWS ElasticCache config commands + // https://github.com/awslabs/aws-elasticache-cluster-client-memcached-for-java/commit/70bf7643963500db20749d97c071b64b954eabb3 + CONFIG_GET { + @Override + public byte fieldValue() { + return 0x60; + + } + }, + CONFIG_SET { + @Override + public byte fieldValue() { + return 0x64; + + } + }, + CONFIG_DEL { + @Override + public byte fieldValue() { + return 0x66; + + } + }; + + public abstract byte fieldValue(); } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/ResponseStatus.java b/src/main/java/net/rubyeye/xmemcached/command/binary/ResponseStatus.java index 0382bb3cb..3d7f51bd8 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/ResponseStatus.java +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/ResponseStatus.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.binary; @@ -30,262 +24,261 @@ */ public enum ResponseStatus { - NO_ERROR { - @Override - public short fieldValue() { - return 0x0000; - } + NO_ERROR { + @Override + public short fieldValue() { + return 0x0000; + } - @Override - public String errorMessage() { - return "No error"; - } - }, - KEY_NOT_FOUND { - @Override - public short fieldValue() { - return 0x0001; - } + @Override + public String errorMessage() { + return "No error"; + } + }, + KEY_NOT_FOUND { + @Override + public short fieldValue() { + return 0x0001; + } - @Override - public String errorMessage() { - return "Key is not found."; - } - }, - KEY_EXISTS { - @Override - public short fieldValue() { - return 0x0002; - } + @Override + public String errorMessage() { + return "Key is not found."; + } + }, + KEY_EXISTS { + @Override + public short fieldValue() { + return 0x0002; + } - @Override - public String errorMessage() { - return "Key is already existed."; - } - }, - VALUE_TOO_BIG { - @Override - public short fieldValue() { - return 0x0003; - } + @Override + public String errorMessage() { + return "Key is already existed."; + } + }, + VALUE_TOO_BIG { + @Override + public short fieldValue() { + return 0x0003; + } - @Override - public String errorMessage() { - return "Value is too big."; - } - }, - INVALID_ARGUMENTS { - @Override - public short fieldValue() { - return 0x0004; - } + @Override + public String errorMessage() { + return "Value is too big."; + } + }, + INVALID_ARGUMENTS { + @Override + public short fieldValue() { + return 0x0004; + } - @Override - public String errorMessage() { - return "Invalid arguments."; - } - }, - ITEM_NOT_STORED { - @Override - public short fieldValue() { - return 0x0005; - } + @Override + public String errorMessage() { + return "Invalid arguments."; + } + }, + ITEM_NOT_STORED { + @Override + public short fieldValue() { + return 0x0005; + } - @Override - public String errorMessage() { - return "Item is not stored."; - } - }, - INC_DEC_NON_NUM { - @Override - public short fieldValue() { - return 0x0006; - } + @Override + public String errorMessage() { + return "Item is not stored."; + } + }, + INC_DEC_NON_NUM { + @Override + public short fieldValue() { + return 0x0006; + } - @Override - public String errorMessage() { - return "Incr/Decr on non-numeric value."; - } - }, - BELONGS_TO_ANOTHER_SRV { - @Override - public short fieldValue() { - return 0x0007; - } + @Override + public String errorMessage() { + return "Incr/Decr on non-numeric value."; + } + }, + BELONGS_TO_ANOTHER_SRV { + @Override + public short fieldValue() { + return 0x0007; + } - @Override - public String errorMessage() { - return "The vbucket belongs to another server."; - } - }, - AUTH_ERROR { - @Override - public short fieldValue() { - return 0x0008; - } + @Override + public String errorMessage() { + return "The vbucket belongs to another server."; + } + }, + AUTH_ERROR { + @Override + public short fieldValue() { + return 0x0008; + } - @Override - public String errorMessage() { - return "Authentication error ."; - } - }, - AUTH_CONTINUE { - @Override - public short fieldValue() { - return 0x0009; - } + @Override + public String errorMessage() { + return "Authentication error ."; + } + }, + AUTH_CONTINUE { + @Override + public short fieldValue() { + return 0x0009; + } - @Override - public String errorMessage() { - return "Authentication continue ."; - } - }, - UNKNOWN_COMMAND { - @Override - public short fieldValue() { - return 0x0081; - } + @Override + public String errorMessage() { + return "Authentication continue ."; + } + }, + UNKNOWN_COMMAND { + @Override + public short fieldValue() { + return 0x0081; + } - @Override - public String errorMessage() { - return "Unknown command error."; - } - }, - OUT_OF_MEMORY { - @Override - public short fieldValue() { - return 0x0082; - } + @Override + public String errorMessage() { + return "Unknown command error."; + } + }, + OUT_OF_MEMORY { + @Override + public short fieldValue() { + return 0x0082; + } - @Override - public String errorMessage() { - return "Out of memory ."; - } - }, - NOT_SUPPORTED { - @Override - public short fieldValue() { - return 0x0083; - } + @Override + public String errorMessage() { + return "Out of memory ."; + } + }, + NOT_SUPPORTED { + @Override + public short fieldValue() { + return 0x0083; + } - @Override - public String errorMessage() { - return "Not supported ."; - } - }, - INTERNAL_ERROR { - @Override - public short fieldValue() { - return 0x0084; - } + @Override + public String errorMessage() { + return "Not supported ."; + } + }, + INTERNAL_ERROR { + @Override + public short fieldValue() { + return 0x0084; + } - @Override - public String errorMessage() { - return "Internal error ."; - } - }, - BUSY { - @Override - public short fieldValue() { - return 0x0085; - } + @Override + public String errorMessage() { + return "Internal error ."; + } + }, + BUSY { + @Override + public short fieldValue() { + return 0x0085; + } - @Override - public String errorMessage() { - return "Busy."; - } - }, + @Override + public String errorMessage() { + return "Busy."; + } + }, - TEMP_FAILURE { - @Override - public short fieldValue() { - return 0x0086; - } + TEMP_FAILURE { + @Override + public short fieldValue() { + return 0x0086; + } - @Override - public String errorMessage() { - return "Temporary failure ."; - } - }, + @Override + public String errorMessage() { + return "Temporary failure ."; + } + }, - AUTH_REQUIRED { - @Override - public short fieldValue() { - return 0x20; - } + AUTH_REQUIRED { + @Override + public short fieldValue() { + return 0x20; + } - @Override - public String errorMessage() { - return "Authentication required or not successful"; - } - }, - FUTHER_AUTH_REQUIRED { - @Override - public short fieldValue() { - return 0x21; - } + @Override + public String errorMessage() { + return "Authentication required or not successful"; + } + }, + FUTHER_AUTH_REQUIRED { + @Override + public short fieldValue() { + return 0x21; + } - @Override - public String errorMessage() { - return "Further authentication steps required. "; - } - }; - abstract short fieldValue(); + @Override + public String errorMessage() { + return "Further authentication steps required. "; + } + }; + abstract short fieldValue(); - /** - * Get status from short value - * - * @param value - * @return - */ - public static ResponseStatus parseShort(short value) { - switch (value) { - case 0x0000 : - return NO_ERROR; - case 0x0001 : - return KEY_NOT_FOUND; - case 0x0002 : - return KEY_EXISTS; - case 0x0003 : - return VALUE_TOO_BIG; - case 0x0004 : - return INVALID_ARGUMENTS; - case 0x0005 : - return ITEM_NOT_STORED; - case 0x0006 : - return INC_DEC_NON_NUM; - case 0x0007 : - return BELONGS_TO_ANOTHER_SRV; - case 0x0008 : - return AUTH_ERROR; - case 0x0009 : - return AUTH_CONTINUE; - case 0x0081 : - return UNKNOWN_COMMAND; - case 0x0082 : - return OUT_OF_MEMORY; - case 0x0083 : - return NOT_SUPPORTED; - case 0x0084 : - return INTERNAL_ERROR; - case 0x0085 : - return BUSY; - case 0x0086 : - return TEMP_FAILURE; - case 0x20 : - return AUTH_REQUIRED; - case 0x21 : - return FUTHER_AUTH_REQUIRED; - default : - throw new IllegalArgumentException( - "Unknow Response status:" + value); - } - } + /** + * Get status from short value + * + * @param value + * @return + */ + public static ResponseStatus parseShort(short value) { + switch (value) { + case 0x0000: + return NO_ERROR; + case 0x0001: + return KEY_NOT_FOUND; + case 0x0002: + return KEY_EXISTS; + case 0x0003: + return VALUE_TOO_BIG; + case 0x0004: + return INVALID_ARGUMENTS; + case 0x0005: + return ITEM_NOT_STORED; + case 0x0006: + return INC_DEC_NON_NUM; + case 0x0007: + return BELONGS_TO_ANOTHER_SRV; + case 0x0008: + return AUTH_ERROR; + case 0x0009: + return AUTH_CONTINUE; + case 0x0081: + return UNKNOWN_COMMAND; + case 0x0082: + return OUT_OF_MEMORY; + case 0x0083: + return NOT_SUPPORTED; + case 0x0084: + return INTERNAL_ERROR; + case 0x0085: + return BUSY; + case 0x0086: + return TEMP_FAILURE; + case 0x20: + return AUTH_REQUIRED; + case 0x21: + return FUTHER_AUTH_REQUIRED; + default: + throw new IllegalArgumentException("Unknow Response status:" + value); + } + } - /** - * The status error message - * - * @return - */ - abstract String errorMessage(); + /** + * The status error message + * + * @return + */ + abstract String errorMessage(); } diff --git a/src/main/java/net/rubyeye/xmemcached/command/binary/package.html b/src/main/java/net/rubyeye/xmemcached/command/binary/package.html index 70072ec08..743d1c92d 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/binary/package.html +++ b/src/main/java/net/rubyeye/xmemcached/command/binary/package.html @@ -1,14 +1,10 @@ - - + - -Memcached text protocol implementations - - - -

Memcached text protocol implementations

- - - + + Memcached text protocol implementations + + +

Memcached text protocol implementations

+ + \ No newline at end of file diff --git a/src/main/java/net/rubyeye/xmemcached/command/kestrel/KestrelDeleteCommand.java b/src/main/java/net/rubyeye/xmemcached/command/kestrel/KestrelDeleteCommand.java index e12d5ab95..d29d5a9ad 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/kestrel/KestrelDeleteCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/kestrel/KestrelDeleteCommand.java @@ -2,51 +2,50 @@ import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.text.TextDeleteCommand; import net.rubyeye.xmemcached.impl.MemcachedTCPSession; import net.rubyeye.xmemcached.utils.ByteUtils; public class KestrelDeleteCommand extends TextDeleteCommand { - public KestrelDeleteCommand(String key, byte[] keyBytes, int time, - CountDownLatch latch, boolean noreply) { - super(key, keyBytes, time, latch, noreply); - } + public KestrelDeleteCommand(String key, byte[] keyBytes, int time, CountDownLatch latch, + boolean noreply) { + super(key, keyBytes, time, latch, noreply); + } - @Override - public boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { - if (buffer == null || !buffer.hasRemaining()) { - return false; - } - if (this.result == null) { - if (buffer.remaining() < 2) { - return false; - } - byte first = buffer.get(buffer.position()); - byte second = buffer.get(buffer.position() + 1); - if (first == 'E' && second == 'N') { - this.setResult(Boolean.TRUE); - this.countDownLatch(); - // END\r\n - return ByteUtils.stepBuffer(buffer, 5); - } else if (first == 'D' && second == 'E') { - this.setResult(Boolean.TRUE); - this.countDownLatch(); - // DELETED\r\n - return ByteUtils.stepBuffer(buffer, 9); - } else { - return this.decodeError(session, buffer); - } - } else { - Boolean result = (Boolean) this.result; - if (result) { - // END\r\n - return ByteUtils.stepBuffer(buffer, 5); - } else { - return this.decodeError(session, buffer); - } - } - } + @Override + public boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { + if (buffer == null || !buffer.hasRemaining()) { + return false; + } + if (this.result == null) { + if (buffer.remaining() < 2) { + return false; + } + byte first = buffer.get(buffer.position()); + byte second = buffer.get(buffer.position() + 1); + if (first == 'E' && second == 'N') { + this.setResult(Boolean.TRUE); + this.countDownLatch(); + // END\r\n + return ByteUtils.stepBuffer(buffer, 5); + } else if (first == 'D' && second == 'E') { + this.setResult(Boolean.TRUE); + this.countDownLatch(); + // DELETED\r\n + return ByteUtils.stepBuffer(buffer, 9); + } else { + return this.decodeError(session, buffer); + } + } else { + Boolean result = (Boolean) this.result; + if (result) { + // END\r\n + return ByteUtils.stepBuffer(buffer, 5); + } else { + return this.decodeError(session, buffer); + } + } + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/kestrel/KestrelFlushAllCommand.java b/src/main/java/net/rubyeye/xmemcached/command/kestrel/KestrelFlushAllCommand.java index d75a1df71..f6fca11ff 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/kestrel/KestrelFlushAllCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/kestrel/KestrelFlushAllCommand.java @@ -1,30 +1,23 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.kestrel; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.text.TextFlushAllCommand; import net.rubyeye.xmemcached.impl.MemcachedTCPSession; import net.rubyeye.xmemcached.utils.ByteUtils; @@ -37,28 +30,27 @@ */ public class KestrelFlushAllCommand extends TextFlushAllCommand { - public KestrelFlushAllCommand(CountDownLatch latch, int delay, - boolean noreply) { - super(latch, delay, noreply); - } + public KestrelFlushAllCommand(CountDownLatch latch, int delay, boolean noreply) { + super(latch, delay, noreply); + } - @Override - public boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { - if (buffer == null || !buffer.hasRemaining()) { - return false; - } - String line = ByteUtils.nextLine(buffer); - if (line == null) { - return false; - } else { - if (line.startsWith("Flushed")) { - setResult(Boolean.TRUE); - countDownLatch(); - return true; - } else { - return decodeError(session, buffer); - } - } - } + @Override + public boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { + if (buffer == null || !buffer.hasRemaining()) { + return false; + } + String line = ByteUtils.nextLine(buffer); + if (line == null) { + return false; + } else { + if (line.startsWith("Flushed")) { + setResult(Boolean.TRUE); + countDownLatch(); + return true; + } else { + return decodeError(session, buffer); + } + } + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/kestrel/KestrelGetCommand.java b/src/main/java/net/rubyeye/xmemcached/command/kestrel/KestrelGetCommand.java index 3b177e62a..438c41cb1 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/kestrel/KestrelGetCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/kestrel/KestrelGetCommand.java @@ -1,79 +1,72 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.kestrel; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.CommandType; import net.rubyeye.xmemcached.command.text.TextGetCommand; import net.rubyeye.xmemcached.transcoders.CachedData; import net.rubyeye.xmemcached.transcoders.Transcoder; import net.rubyeye.xmemcached.transcoders.TranscoderUtils; + /** * Kestrel get command * * @author dennis - * + * */ public class KestrelGetCommand extends TextGetCommand { - public KestrelGetCommand(String key, byte[] keyBytes, CommandType cmdType, - CountDownLatch latch, Transcoder transcoder) { - super(key, keyBytes, cmdType, latch); - this.transcoder = transcoder; - } + public KestrelGetCommand(String key, byte[] keyBytes, CommandType cmdType, CountDownLatch latch, + Transcoder transcoder) { + super(key, keyBytes, cmdType, latch); + this.transcoder = transcoder; + } - public static final TranscoderUtils transcoderUtils = new TranscoderUtils( - false); + public static final TranscoderUtils transcoderUtils = new TranscoderUtils(false); - @Override - public void dispatch() { - if (this.returnValues.size() == 0) { - if (!this.wasFirst) { - decodeError(); - } else { - this.countDownLatch(); - } - } else { - CachedData value = this.returnValues.values().iterator().next(); - // If disable save primitive type as string,the response data have - // 4-bytes flag aheader. - if (!this.transcoder.isPrimitiveAsString()) { - byte[] data = value.getData(); - if (data.length >= 4) { - byte[] flagBytes = new byte[4]; - System.arraycopy(data, 0, flagBytes, 0, 4); - byte[] realData = new byte[data.length - 4]; - System.arraycopy(data, 4, realData, 0, data.length - 4); - int flag = transcoderUtils.decodeInt(flagBytes); - value.setFlag(flag); - value.setData(realData); - value.setCapacity(realData.length); - } - } - setResult(value); - this.countDownLatch(); - } - } + @Override + public void dispatch() { + if (this.returnValues.size() == 0) { + if (!this.wasFirst) { + decodeError(); + } else { + this.countDownLatch(); + } + } else { + CachedData value = this.returnValues.values().iterator().next(); + // If disable save primitive type as string,the response data have + // 4-bytes flag aheader. + if (!this.transcoder.isPrimitiveAsString()) { + byte[] data = value.getData(); + if (data.length >= 4) { + byte[] flagBytes = new byte[4]; + System.arraycopy(data, 0, flagBytes, 0, 4); + byte[] realData = new byte[data.length - 4]; + System.arraycopy(data, 4, realData, 0, data.length - 4); + int flag = transcoderUtils.decodeInt(flagBytes); + value.setFlag(flag); + value.setData(realData); + value.setCapacity(realData.length); + } + } + setResult(value); + this.countDownLatch(); + } + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/kestrel/KestrelSetCommand.java b/src/main/java/net/rubyeye/xmemcached/command/kestrel/KestrelSetCommand.java index 401c6eeed..94ef4646e 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/kestrel/KestrelSetCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/kestrel/KestrelSetCommand.java @@ -1,68 +1,59 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.kestrel; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.CommandType; import net.rubyeye.xmemcached.command.text.TextStoreCommand; import net.rubyeye.xmemcached.transcoders.CachedData; import net.rubyeye.xmemcached.transcoders.Transcoder; + /** * kestrel set command * * @author dennis - * + * */ public class KestrelSetCommand extends TextStoreCommand { - @SuppressWarnings("unchecked") - public KestrelSetCommand(String key, byte[] keyBytes, CommandType cmdType, - CountDownLatch latch, int exp, long cas, Object value, - boolean noreply, Transcoder transcoder) { - super(key, keyBytes, cmdType, latch, exp, cas, value, noreply, - transcoder); - } + @SuppressWarnings("unchecked") + public KestrelSetCommand(String key, byte[] keyBytes, CommandType cmdType, CountDownLatch latch, + int exp, long cas, Object value, boolean noreply, Transcoder transcoder) { + super(key, keyBytes, cmdType, latch, exp, cas, value, noreply, transcoder); + } - @Override - @SuppressWarnings("unchecked") - protected CachedData encodeValue() { + @Override + @SuppressWarnings("unchecked") + protected CachedData encodeValue() { - final CachedData value = this.transcoder.encode(this.value); - // If disable save primitive type as string,prepend 4 bytes flag to - // value - if (!this.transcoder.isPrimitiveAsString()) { - int flags = value.getFlag(); - byte[] flagBytes = KestrelGetCommand.transcoderUtils - .encodeInt(flags); - byte[] origData = value.getData(); - byte[] newData = new byte[origData.length + 4]; - System.arraycopy(flagBytes, 0, newData, 0, 4); - System.arraycopy(origData, 0, newData, 4, origData.length); - value.setCapacity(newData.length); - value.setData(newData); - } - return value; - } + final CachedData value = this.transcoder.encode(this.value); + // If disable save primitive type as string,prepend 4 bytes flag to + // value + if (!this.transcoder.isPrimitiveAsString()) { + int flags = value.getFlag(); + byte[] flagBytes = KestrelGetCommand.transcoderUtils.encodeInt(flags); + byte[] origData = value.getData(); + byte[] newData = new byte[origData.length + 4]; + System.arraycopy(flagBytes, 0, newData, 0, 4); + System.arraycopy(origData, 0, newData, 4, origData.length); + value.setCapacity(newData.length); + value.setData(newData); + } + return value; + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/kestrel/package.html b/src/main/java/net/rubyeye/xmemcached/command/kestrel/package.html index ff6c9204f..2aced3aac 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/kestrel/package.html +++ b/src/main/java/net/rubyeye/xmemcached/command/kestrel/package.html @@ -1,14 +1,10 @@ - - + - -Kestrel protocol implementations - - - -

Kestrel protocol implementations

- - - + + Kestrel protocol implementations + + +

Kestrel protocol implementations

+ + \ No newline at end of file diff --git a/src/main/java/net/rubyeye/xmemcached/command/package.html b/src/main/java/net/rubyeye/xmemcached/command/package.html index 41135e54d..111d0c57b 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/package.html +++ b/src/main/java/net/rubyeye/xmemcached/command/package.html @@ -1,14 +1,13 @@ - - + - -Memcached protocol implementations/title> -</head> - -<body> -<h1>Memcached protocol implementations</h1> -</body> -</html> + <head> + <title>Memcached protocol implementations/title> +</head> + + + +

Memcached protocol implementations

+ + \ No newline at end of file diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextAWSElasticCacheConfigCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextAWSElasticCacheConfigCommand.java index 9447a7aa2..9a3e7ab30 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextAWSElasticCacheConfigCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextAWSElasticCacheConfigCommand.java @@ -1,69 +1,66 @@ -package net.rubyeye.xmemcached.command.text; - -import java.nio.ByteBuffer; -import java.util.concurrent.CountDownLatch; - -import com.google.code.yanf4j.buffer.IoBuffer; - -import net.rubyeye.xmemcached.command.Command; -import net.rubyeye.xmemcached.command.CommandType; -import net.rubyeye.xmemcached.impl.MemcachedTCPSession; -import net.rubyeye.xmemcached.networking.MemcachedSession; -import net.rubyeye.xmemcached.utils.ByteUtils; - -/** - * AWS ElasticCache config command, see Adding Auto Discovery To Your Client Library. Only supports Cache Engine - * version 1.4.14 or higher. - * - * @author dennis - * - */ -public class TextAWSElasticCacheConfigCommand extends Command { - - private String key; - - private String subCommand; - - public TextAWSElasticCacheConfigCommand(final CountDownLatch latch, - String subCommand, String key) { - super(subCommand + key, CommandType.AWS_CONFIG, latch); - this.key = key; - this.subCommand = subCommand; - this.result = new StringBuilder(); - } - - @Override - public boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { - String line = null; - while ((line = ByteUtils.nextLine(buffer)) != null) { - if (line.equals("END")) { // at the end - return done(session); - } else if (line.startsWith("CONFIG")) { - // ignore - } else { - ((StringBuilder) this.getResult()).append(line); - } - } - return false; - } - - private final boolean done(MemcachedSession session) { - setResult(this.getResult().toString()); - countDownLatch(); - return true; - } - - @Override - public void encode() { - // config [sub-command] [key] - final byte[] subCmdBytes = ByteUtils.getBytes(this.subCommand); - final byte[] keyBytes = ByteUtils.getBytes(this.key); - this.ioBuffer = IoBuffer - .allocate(6 + 1 + subCmdBytes.length + 1 + keyBytes.length + 2); - ByteUtils.setArguments(this.ioBuffer, "config", subCmdBytes, keyBytes); - this.ioBuffer.flip(); - } - -} +package net.rubyeye.xmemcached.command.text; + +import java.nio.ByteBuffer; +import java.util.concurrent.CountDownLatch; +import com.google.code.yanf4j.buffer.IoBuffer; +import net.rubyeye.xmemcached.command.Command; +import net.rubyeye.xmemcached.command.CommandType; +import net.rubyeye.xmemcached.impl.MemcachedTCPSession; +import net.rubyeye.xmemcached.networking.MemcachedSession; +import net.rubyeye.xmemcached.utils.ByteUtils; + +/** + * AWS ElasticCache config command, see Adding Auto Discovery To Your Client Library. Only supports Cache Engine version 1.4.14 or + * higher. + * + * @author dennis + * + */ +public class TextAWSElasticCacheConfigCommand extends Command { + + private String key; + + private String subCommand; + + public TextAWSElasticCacheConfigCommand(final CountDownLatch latch, String subCommand, + String key) { + super(subCommand + key, CommandType.AWS_CONFIG, latch); + this.key = key; + this.subCommand = subCommand; + this.result = new StringBuilder(); + } + + @Override + public boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { + String line = null; + while ((line = ByteUtils.nextLine(buffer)) != null) { + if (line.equals("END")) { // at the end + return done(session); + } else if (line.startsWith("CONFIG")) { + // ignore + } else { + ((StringBuilder) this.getResult()).append(line); + } + } + return false; + } + + private final boolean done(MemcachedSession session) { + setResult(this.getResult().toString()); + countDownLatch(); + return true; + } + + @Override + public void encode() { + // config [sub-command] [key] + final byte[] subCmdBytes = ByteUtils.getBytes(this.subCommand); + final byte[] keyBytes = ByteUtils.getBytes(this.key); + this.ioBuffer = IoBuffer.allocate(6 + 1 + subCmdBytes.length + 1 + keyBytes.length + 2); + ByteUtils.setArguments(this.ioBuffer, "config", subCmdBytes, keyBytes); + this.ioBuffer.flip(); + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextCASCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextCASCommand.java index b7e212174..1b6a8f1cc 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextCASCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextCASCommand.java @@ -1,30 +1,23 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.text; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.CommandType; import net.rubyeye.xmemcached.impl.MemcachedTCPSession; import net.rubyeye.xmemcached.transcoders.Transcoder; @@ -38,64 +31,61 @@ */ public class TextCASCommand extends TextStoreCommand { - @SuppressWarnings("unchecked") - public TextCASCommand(String key, byte[] keyBytes, CommandType cmdType, - CountDownLatch latch, int exp, long cas, Object value, - boolean noreply, Transcoder transcoder) { - super(key, keyBytes, cmdType, latch, exp, cas, value, noreply, - transcoder); - } + @SuppressWarnings("unchecked") + public TextCASCommand(String key, byte[] keyBytes, CommandType cmdType, CountDownLatch latch, + int exp, long cas, Object value, boolean noreply, Transcoder transcoder) { + super(key, keyBytes, cmdType, latch, exp, cas, value, noreply, transcoder); + } - private FailStatus failStatus; + private FailStatus failStatus; - static enum FailStatus { - NOT_FOUND, EXISTS - } + static enum FailStatus { + NOT_FOUND, EXISTS + } - @Override - public final boolean decode(MemcachedTCPSession session, - ByteBuffer buffer) { + @Override + public final boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { - if (buffer == null || !buffer.hasRemaining()) - return false; - if (result == null) { - if (buffer.remaining() < 2) - return false; - byte first = buffer.get(buffer.position()); - byte second = buffer.get(buffer.position() + 1); - if (first == 'S' && second == 'T') { - setResult(Boolean.TRUE); - countDownLatch(); - // STORED\r\n - return ByteUtils.stepBuffer(buffer, 8); - } else if (first == 'N') { - setResult(Boolean.FALSE); - countDownLatch(); - failStatus = FailStatus.NOT_FOUND; - // NOT_FOUND\r\n - return ByteUtils.stepBuffer(buffer, 11); - } else if (first == 'E' && second == 'X') { - setResult(Boolean.FALSE); - countDownLatch(); - failStatus = FailStatus.EXISTS; - // EXISTS\r\n - return ByteUtils.stepBuffer(buffer, 8); - } else - return decodeError(session, buffer); - } else { - Boolean result = (Boolean) this.result; - if (result) { - return ByteUtils.stepBuffer(buffer, 8); - } else { - switch (this.failStatus) { - case NOT_FOUND : - return ByteUtils.stepBuffer(buffer, 11); - case EXISTS : - return ByteUtils.stepBuffer(buffer, 8); - default : - return decodeError(session, buffer); - } - } - } - } + if (buffer == null || !buffer.hasRemaining()) + return false; + if (result == null) { + if (buffer.remaining() < 2) + return false; + byte first = buffer.get(buffer.position()); + byte second = buffer.get(buffer.position() + 1); + if (first == 'S' && second == 'T') { + setResult(Boolean.TRUE); + countDownLatch(); + // STORED\r\n + return ByteUtils.stepBuffer(buffer, 8); + } else if (first == 'N') { + setResult(Boolean.FALSE); + countDownLatch(); + failStatus = FailStatus.NOT_FOUND; + // NOT_FOUND\r\n + return ByteUtils.stepBuffer(buffer, 11); + } else if (first == 'E' && second == 'X') { + setResult(Boolean.FALSE); + countDownLatch(); + failStatus = FailStatus.EXISTS; + // EXISTS\r\n + return ByteUtils.stepBuffer(buffer, 8); + } else + return decodeError(session, buffer); + } else { + Boolean result = (Boolean) this.result; + if (result) { + return ByteUtils.stepBuffer(buffer, 8); + } else { + switch (this.failStatus) { + case NOT_FOUND: + return ByteUtils.stepBuffer(buffer, 11); + case EXISTS: + return ByteUtils.stepBuffer(buffer, 8); + default: + return decodeError(session, buffer); + } + } + } + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextCacheDumpCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextCacheDumpCommand.java index 5b5bb84e9..fc25afa77 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextCacheDumpCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextCacheDumpCommand.java @@ -4,60 +4,57 @@ import java.util.LinkedList; import java.util.List; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.Command; import net.rubyeye.xmemcached.command.CommandType; import net.rubyeye.xmemcached.impl.MemcachedTCPSession; import net.rubyeye.xmemcached.networking.MemcachedSession; import net.rubyeye.xmemcached.utils.ByteUtils; - import com.google.code.yanf4j.buffer.IoBuffer; public class TextCacheDumpCommand extends Command { - public static final String CACHE_DUMP_COMMAND = "stats cachedump %d 0\r\n"; - private int itemNumber; - - public final int getItemNumber() { - return this.itemNumber; - } - - public final void setItemNumber(int itemNumber) { - this.itemNumber = itemNumber; - } - - public TextCacheDumpCommand(CountDownLatch latch, int itemNumber) { - super("stats", (byte[]) null, latch); - this.commandType = CommandType.STATS; - this.result = new LinkedList(); - this.itemNumber = itemNumber; - } - - @Override - @SuppressWarnings("unchecked") - public final boolean decode(MemcachedTCPSession session, - ByteBuffer buffer) { - String line = null; - while ((line = ByteUtils.nextLine(buffer)) != null) { - if (line.equals("END")) { // at the end - return done(session); - } else if (line.startsWith("ITEM")) { - String[] items = line.split(" "); - ((List) getResult()).add(items[1]); - } else { - return decodeError(line); - } - } - return false; - } - - private final boolean done(MemcachedSession session) { - countDownLatch(); - return true; - } - - @Override - public final void encode() { - String result = String.format(CACHE_DUMP_COMMAND, this.itemNumber); - this.ioBuffer = IoBuffer.wrap(ByteBuffer.wrap(result.getBytes())); - } + public static final String CACHE_DUMP_COMMAND = "stats cachedump %d 0\r\n"; + private int itemNumber; + + public final int getItemNumber() { + return this.itemNumber; + } + + public final void setItemNumber(int itemNumber) { + this.itemNumber = itemNumber; + } + + public TextCacheDumpCommand(CountDownLatch latch, int itemNumber) { + super("stats", (byte[]) null, latch); + this.commandType = CommandType.STATS; + this.result = new LinkedList(); + this.itemNumber = itemNumber; + } + + @Override + @SuppressWarnings("unchecked") + public final boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { + String line = null; + while ((line = ByteUtils.nextLine(buffer)) != null) { + if (line.equals("END")) { // at the end + return done(session); + } else if (line.startsWith("ITEM")) { + String[] items = line.split(" "); + ((List) getResult()).add(items[1]); + } else { + return decodeError(line); + } + } + return false; + } + + private final boolean done(MemcachedSession session) { + countDownLatch(); + return true; + } + + @Override + public final void encode() { + String result = String.format(CACHE_DUMP_COMMAND, this.itemNumber); + this.ioBuffer = IoBuffer.wrap(ByteBuffer.wrap(result.getBytes())); + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextDeleteCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextDeleteCommand.java index b55de2e3e..f67192372 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextDeleteCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextDeleteCommand.java @@ -1,36 +1,28 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.text; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.Command; import net.rubyeye.xmemcached.command.CommandType; import net.rubyeye.xmemcached.impl.MemcachedTCPSession; import net.rubyeye.xmemcached.monitor.Constants; import net.rubyeye.xmemcached.utils.ByteUtils; - import com.google.code.yanf4j.buffer.IoBuffer; /** @@ -41,69 +33,67 @@ */ public class TextDeleteCommand extends Command { - protected int time; + protected int time; - public TextDeleteCommand(String key, byte[] keyBytes, int time, - final CountDownLatch latch, boolean noreply) { - super(key, keyBytes, latch); - this.commandType = CommandType.DELETE; - this.time = time; - this.noreply = noreply; - } + public TextDeleteCommand(String key, byte[] keyBytes, int time, final CountDownLatch latch, + boolean noreply) { + super(key, keyBytes, latch); + this.commandType = CommandType.DELETE; + this.time = time; + this.noreply = noreply; + } - public final int getTime() { - return this.time; - } + public final int getTime() { + return this.time; + } - public final void setTime(int time) { - this.time = time; - } + public final void setTime(int time) { + this.time = time; + } - @Override - public boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { - if (buffer == null || !buffer.hasRemaining()) { - return false; - } - if (this.result == null) { - byte first = buffer.get(buffer.position()); - if (first == 'D') { - setResult(Boolean.TRUE); - countDownLatch(); - // DELETED\r\n - return ByteUtils.stepBuffer(buffer, 9); - } else if (first == 'N') { - setResult(Boolean.FALSE); - countDownLatch(); - // NOT_FOUND\r\n - return ByteUtils.stepBuffer(buffer, 11); - } else { - return decodeError(session, buffer); - } - } else { - Boolean result = (Boolean) this.result; - if (result) { - return ByteUtils.stepBuffer(buffer, 9); - } else { - return ByteUtils.stepBuffer(buffer, 11); - } - } - } + @Override + public boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { + if (buffer == null || !buffer.hasRemaining()) { + return false; + } + if (this.result == null) { + byte first = buffer.get(buffer.position()); + if (first == 'D') { + setResult(Boolean.TRUE); + countDownLatch(); + // DELETED\r\n + return ByteUtils.stepBuffer(buffer, 9); + } else if (first == 'N') { + setResult(Boolean.FALSE); + countDownLatch(); + // NOT_FOUND\r\n + return ByteUtils.stepBuffer(buffer, 11); + } else { + return decodeError(session, buffer); + } + } else { + Boolean result = (Boolean) this.result; + if (result) { + return ByteUtils.stepBuffer(buffer, 9); + } else { + return ByteUtils.stepBuffer(buffer, 11); + } + } + } - @Override - public final void encode() { - int size = Constants.DELETE.length + 1 + this.keyBytes.length - + Constants.CRLF.length; - if (isNoreply()) { - size += 8; - } - byte[] buf = new byte[size]; - if (isNoreply()) { - ByteUtils.setArguments(buf, 0, Constants.DELETE, this.keyBytes, - Constants.NO_REPLY); - } else { - ByteUtils.setArguments(buf, 0, Constants.DELETE, this.keyBytes); - } - this.ioBuffer = IoBuffer.wrap(buf); - } + @Override + public final void encode() { + int size = Constants.DELETE.length + 1 + this.keyBytes.length + Constants.CRLF.length; + if (isNoreply()) { + size += 8; + } + byte[] buf = new byte[size]; + if (isNoreply()) { + ByteUtils.setArguments(buf, 0, Constants.DELETE, this.keyBytes, Constants.NO_REPLY); + } else { + ByteUtils.setArguments(buf, 0, Constants.DELETE, this.keyBytes); + } + this.ioBuffer = IoBuffer.wrap(buf); + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextFlushAllCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextFlushAllCommand.java index e2d4d7d7b..5ce621396 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextFlushAllCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextFlushAllCommand.java @@ -1,36 +1,28 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.text; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.Command; import net.rubyeye.xmemcached.command.CommandType; import net.rubyeye.xmemcached.impl.MemcachedTCPSession; import net.rubyeye.xmemcached.monitor.Constants; import net.rubyeye.xmemcached.utils.ByteUtils; - import com.google.code.yanf4j.buffer.IoBuffer; /** @@ -41,72 +33,64 @@ */ public class TextFlushAllCommand extends Command { - public static final ByteBuffer FLUSH_ALL = ByteBuffer - .wrap("flush_all\r\n".getBytes()); + public static final ByteBuffer FLUSH_ALL = ByteBuffer.wrap("flush_all\r\n".getBytes()); - protected int exptime; + protected int exptime; - public final int getExptime() { - return this.exptime; - } + public final int getExptime() { + return this.exptime; + } - public TextFlushAllCommand(final CountDownLatch latch, int delay, - boolean noreply) { - super("[flush_all]", (byte[]) null, latch); - this.commandType = CommandType.FLUSH_ALL; - this.exptime = delay; - this.noreply = noreply; - } + public TextFlushAllCommand(final CountDownLatch latch, int delay, boolean noreply) { + super("[flush_all]", (byte[]) null, latch); + this.commandType = CommandType.FLUSH_ALL; + this.exptime = delay; + this.noreply = noreply; + } - @Override - public boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { - if (buffer == null || !buffer.hasRemaining()) { - return false; - } - if (this.result == null) { - byte first = buffer.get(buffer.position()); - if (first == 'O') { - setResult(Boolean.TRUE); - countDownLatch(); - // OK\r\n - return ByteUtils.stepBuffer(buffer, 4); - } else { - return decodeError(session, buffer); - } - } else { - return ByteUtils.stepBuffer(buffer, 4); - } - } + @Override + public boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { + if (buffer == null || !buffer.hasRemaining()) { + return false; + } + if (this.result == null) { + byte first = buffer.get(buffer.position()); + if (first == 'O') { + setResult(Boolean.TRUE); + countDownLatch(); + // OK\r\n + return ByteUtils.stepBuffer(buffer, 4); + } else { + return decodeError(session, buffer); + } + } else { + return ByteUtils.stepBuffer(buffer, 4); + } + } - @Override - public final void encode() { - if (isNoreply()) { - if (this.exptime <= 0) { - this.ioBuffer = IoBuffer.allocate("flush_all".length() + 1 - + Constants.NO_REPLY.length + 2); - ByteUtils.setArguments(this.ioBuffer, "flush_all", - Constants.NO_REPLY); - } else { - byte[] delayBytes = ByteUtils - .getBytes(String.valueOf(this.exptime)); - this.ioBuffer = IoBuffer.allocate("flush_all".length() + 2 - + delayBytes.length + Constants.NO_REPLY.length + 2); - ByteUtils.setArguments(this.ioBuffer, "flush_all", delayBytes, - Constants.NO_REPLY); - } - this.ioBuffer.flip(); - } else { - if (this.exptime <= 0) { - this.ioBuffer = IoBuffer.wrap(FLUSH_ALL.slice()); - } else { + @Override + public final void encode() { + if (isNoreply()) { + if (this.exptime <= 0) { + this.ioBuffer = IoBuffer.allocate("flush_all".length() + 1 + Constants.NO_REPLY.length + 2); + ByteUtils.setArguments(this.ioBuffer, "flush_all", Constants.NO_REPLY); + } else { + byte[] delayBytes = ByteUtils.getBytes(String.valueOf(this.exptime)); + this.ioBuffer = IoBuffer + .allocate("flush_all".length() + 2 + delayBytes.length + Constants.NO_REPLY.length + 2); + ByteUtils.setArguments(this.ioBuffer, "flush_all", delayBytes, Constants.NO_REPLY); + } + this.ioBuffer.flip(); + } else { + if (this.exptime <= 0) { + this.ioBuffer = IoBuffer.wrap(FLUSH_ALL.slice()); + } else { - byte[] delayBytes = ByteUtils - .getBytes(String.valueOf(this.exptime)); - this.ioBuffer = IoBuffer.allocate( - "flush_all".length() + 1 + delayBytes.length + 2); - ByteUtils.setArguments(this.ioBuffer, "flush_all", delayBytes); - } - } - } + byte[] delayBytes = ByteUtils.getBytes(String.valueOf(this.exptime)); + this.ioBuffer = IoBuffer.allocate("flush_all".length() + 1 + delayBytes.length + 2); + ByteUtils.setArguments(this.ioBuffer, "flush_all", delayBytes); + } + } + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextGetCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextGetCommand.java index 5eeba5b59..8f5b6054c 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextGetCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextGetCommand.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.text; @@ -28,7 +22,6 @@ import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.AssocCommandAware; import net.rubyeye.xmemcached.command.Command; import net.rubyeye.xmemcached.command.CommandType; @@ -38,7 +31,6 @@ import net.rubyeye.xmemcached.monitor.Constants; import net.rubyeye.xmemcached.transcoders.CachedData; import net.rubyeye.xmemcached.utils.ByteUtils; - import com.google.code.yanf4j.buffer.IoBuffer; /** @@ -48,283 +40,268 @@ * */ public abstract class TextGetCommand extends Command - implements - MergeCommandsAware, - AssocCommandAware, - MapReturnValueAware { - protected Map returnValues; - private String currentReturnKey; - private int offset; - /** - * When MemcachedClient merge get commands,those commans which have the same - * key will be merged into one get command.The result command's - * assocCommands contains all these commands with the same key. - */ - protected List assocCommands; + implements MergeCommandsAware, AssocCommandAware, MapReturnValueAware { + protected Map returnValues; + private String currentReturnKey; + private int offset; + /** + * When MemcachedClient merge get commands,those commans which have the same key will be merged + * into one get command.The result command's assocCommands contains all these commands with the + * same key. + */ + protected List assocCommands; - protected Map mergeCommands; + protected Map mergeCommands; - public final Map getMergeCommands() { - return this.mergeCommands; - } + public final Map getMergeCommands() { + return this.mergeCommands; + } - public final void setMergeCommands(Map mergeCommands) { - this.mergeCommands = mergeCommands; - } + public final void setMergeCommands(Map mergeCommands) { + this.mergeCommands = mergeCommands; + } - public final List getAssocCommands() { - return this.assocCommands; - } + public final List getAssocCommands() { + return this.assocCommands; + } - public final void setAssocCommands(List assocCommands) { - this.assocCommands = assocCommands; - } + public final void setAssocCommands(List assocCommands) { + this.assocCommands = assocCommands; + } - public TextGetCommand(String key, byte[] keyBytes, CommandType cmdType, - CountDownLatch latch) { - super(key, keyBytes, cmdType, latch); - this.returnValues = new HashMap(32); - } + public TextGetCommand(String key, byte[] keyBytes, CommandType cmdType, CountDownLatch latch) { + super(key, keyBytes, cmdType, latch); + this.returnValues = new HashMap(32); + } - private ParseStatus parseStatus = ParseStatus.NULL; + private ParseStatus parseStatus = ParseStatus.NULL; - public static enum ParseStatus { - NULL, VALUE, KEY, FLAG, DATA_LEN, DATA_LEN_DONE, CAS, CAS_DONE, DATA, END - } + public static enum ParseStatus { + NULL, VALUE, KEY, FLAG, DATA_LEN, DATA_LEN_DONE, CAS, CAS_DONE, DATA, END + } - protected boolean wasFirst = true; + protected boolean wasFirst = true; - public ParseStatus getParseStatus() { - return this.parseStatus; - } + public ParseStatus getParseStatus() { + return this.parseStatus; + } - public void setParseStatus(ParseStatus parseStatus) { - this.parseStatus = parseStatus; - } + public void setParseStatus(ParseStatus parseStatus) { + this.parseStatus = parseStatus; + } - @Override - public final boolean decode(MemcachedTCPSession session, - ByteBuffer buffer) { - while (true) { - if (buffer == null || !buffer.hasRemaining()) { - return false; - } - switch (this.parseStatus) { + @Override + public final boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { + while (true) { + if (buffer == null || !buffer.hasRemaining()) { + return false; + } + switch (this.parseStatus) { - case NULL : - if (buffer.remaining() < 2) - return false; - int pos = buffer.position(); - byte first = buffer.get(pos); - byte second = buffer.get(pos + 1); - if (first == 'E' && second == 'N') { - this.parseStatus = ParseStatus.END; - // dispatch result - dispatch(); - this.currentReturnKey = null; - continue; - } else if (first == 'V') { - this.parseStatus = ParseStatus.VALUE; - this.wasFirst = false; - continue; - } else { - return decodeError(session, buffer); - } - case END : - // END\r\n - return ByteUtils.stepBuffer(buffer, 5); - case VALUE : - // VALUE[SPACE] - if (ByteUtils.stepBuffer(buffer, 6)) { - this.parseStatus = ParseStatus.KEY; - continue; - } else { - return false; - } - case KEY : - String item = getItem(buffer, ' '); - if (item == null) { - return false; - } else { - this.currentReturnKey = item; - this.returnValues.put(this.currentReturnKey, - new CachedData()); - this.parseStatus = ParseStatus.FLAG; - continue; - } - case FLAG : - item = getItem(buffer, ' '); - if (item == null) { - return false; - } else { - final CachedData cachedData = this.returnValues - .get(this.currentReturnKey); - cachedData.setFlag(Integer.parseInt(item)); - this.parseStatus = ParseStatus.DATA_LEN; - continue; - } - case DATA_LEN : - item = getItem(buffer, '\r', ' '); - if (item == null) { - return false; - } else { - final CachedData cachedData = this.returnValues - .get(this.currentReturnKey); - cachedData.setCapacity(Integer.parseInt(item)); - assert (cachedData.getCapacity() >= 0); - cachedData.setData(new byte[cachedData.getCapacity()]); - this.parseStatus = ParseStatus.DATA_LEN_DONE; - continue; - } - case DATA_LEN_DONE : - if (buffer.remaining() < 1) { - return false; - } else { - pos = buffer.position(); - first = buffer.get(pos); - // check if buffer has cas value - if (first == '\n') { - // skip '\n' - buffer.position(pos + 1); - this.parseStatus = ParseStatus.DATA; - continue; - } else { - this.parseStatus = ParseStatus.CAS; - continue; - } - } - case CAS : - // has cas value - item = getItem(buffer, '\r'); - if (item == null) { - return false; - } else { - final CachedData cachedData = this.returnValues - .get(this.currentReturnKey); - cachedData.setCas(Long.parseLong(item)); - this.parseStatus = ParseStatus.CAS_DONE; - continue; - } - case CAS_DONE : - if (buffer.remaining() < 1) { - return false; - } else { - this.parseStatus = ParseStatus.DATA; - // skip '\n' - buffer.position(buffer.position() + 1); - continue; - } - case DATA : - final CachedData value = this.returnValues - .get(this.currentReturnKey); - int remaining = buffer.remaining(); - int remainingCapacity = value.remainingCapacity(); - assert (remainingCapacity >= 0); - // Data is not enough,return false - if (remaining < remainingCapacity + 2) { - int length = remaining > remainingCapacity - ? remainingCapacity - : remaining; - value.fillData(buffer, length); - return false; - } else if (remainingCapacity > 0) { - value.fillData(buffer, remainingCapacity); - } - assert (value.remainingCapacity() == 0); - buffer.position( - buffer.position() + ByteUtils.SPLIT.remaining()); + case NULL: + if (buffer.remaining() < 2) + return false; + int pos = buffer.position(); + byte first = buffer.get(pos); + byte second = buffer.get(pos + 1); + if (first == 'E' && second == 'N') { + this.parseStatus = ParseStatus.END; + // dispatch result + dispatch(); + this.currentReturnKey = null; + continue; + } else if (first == 'V') { + this.parseStatus = ParseStatus.VALUE; + this.wasFirst = false; + continue; + } else { + return decodeError(session, buffer); + } + case END: + // END\r\n + return ByteUtils.stepBuffer(buffer, 5); + case VALUE: + // VALUE[SPACE] + if (ByteUtils.stepBuffer(buffer, 6)) { + this.parseStatus = ParseStatus.KEY; + continue; + } else { + return false; + } + case KEY: + String item = getItem(buffer, ' '); + if (item == null) { + return false; + } else { + this.currentReturnKey = item; + this.returnValues.put(this.currentReturnKey, new CachedData()); + this.parseStatus = ParseStatus.FLAG; + continue; + } + case FLAG: + item = getItem(buffer, ' '); + if (item == null) { + return false; + } else { + final CachedData cachedData = this.returnValues.get(this.currentReturnKey); + cachedData.setFlag(Integer.parseInt(item)); + this.parseStatus = ParseStatus.DATA_LEN; + continue; + } + case DATA_LEN: + item = getItem(buffer, '\r', ' '); + if (item == null) { + return false; + } else { + final CachedData cachedData = this.returnValues.get(this.currentReturnKey); + cachedData.setCapacity(Integer.parseInt(item)); + assert (cachedData.getCapacity() >= 0); + cachedData.setData(new byte[cachedData.getCapacity()]); + this.parseStatus = ParseStatus.DATA_LEN_DONE; + continue; + } + case DATA_LEN_DONE: + if (buffer.remaining() < 1) { + return false; + } else { + pos = buffer.position(); + first = buffer.get(pos); + // check if buffer has cas value + if (first == '\n') { + // skip '\n' + buffer.position(pos + 1); + this.parseStatus = ParseStatus.DATA; + continue; + } else { + this.parseStatus = ParseStatus.CAS; + continue; + } + } + case CAS: + // has cas value + item = getItem(buffer, '\r'); + if (item == null) { + return false; + } else { + final CachedData cachedData = this.returnValues.get(this.currentReturnKey); + cachedData.setCas(Long.parseLong(item)); + this.parseStatus = ParseStatus.CAS_DONE; + continue; + } + case CAS_DONE: + if (buffer.remaining() < 1) { + return false; + } else { + this.parseStatus = ParseStatus.DATA; + // skip '\n' + buffer.position(buffer.position() + 1); + continue; + } + case DATA: + final CachedData value = this.returnValues.get(this.currentReturnKey); + int remaining = buffer.remaining(); + int remainingCapacity = value.remainingCapacity(); + assert (remainingCapacity >= 0); + // Data is not enough,return false + if (remaining < remainingCapacity + 2) { + int length = remaining > remainingCapacity ? remainingCapacity : remaining; + value.fillData(buffer, length); + return false; + } else if (remainingCapacity > 0) { + value.fillData(buffer, remainingCapacity); + } + assert (value.remainingCapacity() == 0); + buffer.position(buffer.position() + ByteUtils.SPLIT.remaining()); - Map mergetCommands = getMergeCommands(); - if (mergetCommands != null) { - final TextGetCommand command = (TextGetCommand) mergetCommands - .remove(this.currentReturnKey); - if (command != null) { - command.setResult(value); - command.countDownLatch(); - this.mergeCount--; - if (command.getAssocCommands() != null) { - for (Command assocCommand : command - .getAssocCommands()) { - assocCommand.setResult(value); - assocCommand.countDownLatch(); - this.mergeCount--; - } - } + Map mergetCommands = getMergeCommands(); + if (mergetCommands != null) { + final TextGetCommand command = + (TextGetCommand) mergetCommands.remove(this.currentReturnKey); + if (command != null) { + command.setResult(value); + command.countDownLatch(); + this.mergeCount--; + if (command.getAssocCommands() != null) { + for (Command assocCommand : command.getAssocCommands()) { + assocCommand.setResult(value); + assocCommand.countDownLatch(); + this.mergeCount--; + } + } - } - } - this.currentReturnKey = null; - this.parseStatus = ParseStatus.NULL; - continue; - default : - return decodeError(session, buffer); - } + } + } + this.currentReturnKey = null; + this.parseStatus = ParseStatus.NULL; + continue; + default: + return decodeError(session, buffer); + } - } - } + } + } - private String getItem(ByteBuffer buffer, char token, char... others) { - int pos = buffer.position() + this.offset; - final int limit = buffer.limit(); - for (; pos < limit; pos++) { - final byte b = buffer.get(pos); - if (b == token || isIn(b, others)) { - byte[] keyBytes = new byte[pos - buffer.position()]; - buffer.get(keyBytes); - this.offset = 0; - assert (pos == buffer.position()); - // skip token - buffer.position(pos + 1); - return getString(keyBytes); - } - } - this.offset = pos - buffer.position(); - return null; - } + private String getItem(ByteBuffer buffer, char token, char... others) { + int pos = buffer.position() + this.offset; + final int limit = buffer.limit(); + for (; pos < limit; pos++) { + final byte b = buffer.get(pos); + if (b == token || isIn(b, others)) { + byte[] keyBytes = new byte[pos - buffer.position()]; + buffer.get(keyBytes); + this.offset = 0; + assert (pos == buffer.position()); + // skip token + buffer.position(pos + 1); + return getString(keyBytes); + } + } + this.offset = pos - buffer.position(); + return null; + } - private boolean isIn(byte b, char[] others) { - for (int i = 0; i < others.length; i++) { - if (b == others[i]) { - return true; - } - } - return false; - } + private boolean isIn(byte b, char[] others) { + for (int i = 0; i < others.length; i++) { + if (b == others[i]) { + return true; + } + } + return false; + } - private String getString(byte[] keyBytes) { - try { - return new String(keyBytes, "utf-8"); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - } + private String getString(byte[] keyBytes) { + try { + return new String(keyBytes, "utf-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } - /* - * (non-Javadoc) - * - * @see - * net.rubyeye.xmemcached.command.text.MapReturnValueAware#getReturnValues() - */ - public final Map getReturnValues() { - return this.returnValues; - } + /* + * (non-Javadoc) + * + * @see net.rubyeye.xmemcached.command.text.MapReturnValueAware#getReturnValues() + */ + public final Map getReturnValues() { + return this.returnValues; + } - public final void setReturnValues(Map returnValues) { - this.returnValues = returnValues; - } + public final void setReturnValues(Map returnValues) { + this.returnValues = returnValues; + } - public abstract void dispatch(); + public abstract void dispatch(); - @Override - public void encode() { - byte[] cmdBytes = this.commandType == CommandType.GET_ONE - || this.commandType == CommandType.GET_MANY - ? Constants.GET - : Constants.GETS; - this.ioBuffer = IoBuffer.allocate(cmdBytes.length - + Constants.CRLF.length + 1 + this.keyBytes.length); - ByteUtils.setArguments(this.ioBuffer, cmdBytes, this.keyBytes); - this.ioBuffer.flip(); - } + @Override + public void encode() { + byte[] cmdBytes = + this.commandType == CommandType.GET_ONE || this.commandType == CommandType.GET_MANY + ? Constants.GET + : Constants.GETS; + this.ioBuffer = + IoBuffer.allocate(cmdBytes.length + Constants.CRLF.length + 1 + this.keyBytes.length); + ByteUtils.setArguments(this.ioBuffer, cmdBytes, this.keyBytes); + this.ioBuffer.flip(); + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextGetMultiCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextGetMultiCommand.java index 2ac6bda20..4b2f99e89 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextGetMultiCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextGetMultiCommand.java @@ -1,49 +1,43 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.text; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.CommandType; import net.rubyeye.xmemcached.transcoders.Transcoder; + /** * Bulk-get command for text protocol * * @author dennis - * + * */ public class TextGetMultiCommand extends TextGetCommand { - @SuppressWarnings("unchecked") - public TextGetMultiCommand(String key, byte[] keyBytes, CommandType cmdType, - CountDownLatch latch, Transcoder transcoder) { - super(key, keyBytes, cmdType, latch); - this.transcoder = transcoder; - } + @SuppressWarnings("unchecked") + public TextGetMultiCommand(String key, byte[] keyBytes, CommandType cmdType, CountDownLatch latch, + Transcoder transcoder) { + super(key, keyBytes, cmdType, latch); + this.transcoder = transcoder; + } - @Override - public final void dispatch() { - setResult(this.returnValues); - countDownLatch(); - } + @Override + public final void dispatch() { + setResult(this.returnValues); + countDownLatch(); + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextGetOneCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextGetOneCommand.java index e3f4326f6..693c24ca7 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextGetOneCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextGetOneCommand.java @@ -1,30 +1,23 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.text; import java.util.Collection; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.Command; import net.rubyeye.xmemcached.command.CommandType; import net.rubyeye.xmemcached.transcoders.CachedData; @@ -37,39 +30,38 @@ */ public class TextGetOneCommand extends TextGetCommand { - public TextGetOneCommand(String key, byte[] keyBytes, CommandType cmdType, - CountDownLatch latch) { - super(key, keyBytes, cmdType, latch); - } + public TextGetOneCommand(String key, byte[] keyBytes, CommandType cmdType, CountDownLatch latch) { + super(key, keyBytes, cmdType, latch); + } - @Override - public void dispatch() { - if (this.mergeCount < 0) { - // single get - if (this.returnValues.get(this.getKey()) == null) { - if (!this.wasFirst) { - decodeError(); - } else { - this.countDownLatch(); - } - } else { - CachedData data = this.returnValues.get(this.getKey()); - setResult(data); - this.countDownLatch(); - } - } else { - // merge get - // Collection mergeCommands = mergeCommands.values(); - getIoBuffer().free(); - for (Command nextCommand : mergeCommands.values()) { - TextGetCommand textGetCommand = (TextGetCommand) nextCommand; - textGetCommand.countDownLatch(); - if (textGetCommand.assocCommands != null) { - for (Command assocCommand : textGetCommand.assocCommands) { - assocCommand.countDownLatch(); - } - } - } - } - } + @Override + public void dispatch() { + if (this.mergeCount < 0) { + // single get + if (this.returnValues.get(this.getKey()) == null) { + if (!this.wasFirst) { + decodeError(); + } else { + this.countDownLatch(); + } + } else { + CachedData data = this.returnValues.get(this.getKey()); + setResult(data); + this.countDownLatch(); + } + } else { + // merge get + // Collection mergeCommands = mergeCommands.values(); + getIoBuffer().free(); + for (Command nextCommand : mergeCommands.values()) { + TextGetCommand textGetCommand = (TextGetCommand) nextCommand; + textGetCommand.countDownLatch(); + if (textGetCommand.assocCommands != null) { + for (Command assocCommand : textGetCommand.assocCommands) { + assocCommand.countDownLatch(); + } + } + } + } + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextIncrDecrCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextIncrDecrCommand.java index 0624ea607..8a195799b 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextIncrDecrCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextIncrDecrCommand.java @@ -1,36 +1,28 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.text; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.Command; import net.rubyeye.xmemcached.command.CommandType; import net.rubyeye.xmemcached.impl.MemcachedTCPSession; import net.rubyeye.xmemcached.monitor.Constants; import net.rubyeye.xmemcached.utils.ByteUtils; - import com.google.code.yanf4j.buffer.IoBuffer; /** @@ -41,69 +33,64 @@ */ public class TextIncrDecrCommand extends Command { - private long delta; - private final long initial; + private long delta; + private final long initial; - public TextIncrDecrCommand(String key, byte[] keyBytes, CommandType cmdType, - CountDownLatch latch, long delta, long initial, boolean noreply) { - super(key, keyBytes, cmdType, latch); - this.delta = delta; - this.noreply = noreply; - this.initial = initial; - } + public TextIncrDecrCommand(String key, byte[] keyBytes, CommandType cmdType, CountDownLatch latch, + long delta, long initial, boolean noreply) { + super(key, keyBytes, cmdType, latch); + this.delta = delta; + this.noreply = noreply; + this.initial = initial; + } - public final long getDelta() { - return this.delta; - } + public final long getDelta() { + return this.delta; + } - public final void setDelta(int delta) { - this.delta = delta; - } + public final void setDelta(int delta) { + this.delta = delta; + } - @Override - public final boolean decode(MemcachedTCPSession session, - ByteBuffer buffer) { - String line = ByteUtils.nextLine(buffer); - if (line != null) { - if (line.equals("NOT_FOUND")) { - // setException(new MemcachedException( - // "The key's value is not found for increase or decrease")); - setResult("NOT_FOUND"); - countDownLatch(); - return true; - } else { - String rt = line.trim(); - if (Character.isDigit(rt.charAt(0))) { - setResult(Long.valueOf(rt)); - countDownLatch(); - return true; - } else { - return decodeError(line); - } - } - } - return false; - } + @Override + public final boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { + String line = ByteUtils.nextLine(buffer); + if (line != null) { + if (line.equals("NOT_FOUND")) { + // setException(new MemcachedException( + // "The key's value is not found for increase or decrease")); + setResult("NOT_FOUND"); + countDownLatch(); + return true; + } else { + String rt = line.trim(); + if (Character.isDigit(rt.charAt(0))) { + setResult(Long.valueOf(rt)); + countDownLatch(); + return true; + } else { + return decodeError(line); + } + } + } + return false; + } - @Override - public final void encode() { - byte[] cmdBytes = this.commandType == CommandType.INCR - ? Constants.INCR - : Constants.DECR; - int size = 6 + this.keyBytes.length - + ByteUtils.stringSize(this.getDelta()) + Constants.CRLF.length; - if (isNoreply()) { - size += 8; - } - byte[] buf = new byte[size]; - if (isNoreply()) { - ByteUtils.setArguments(buf, 0, cmdBytes, this.keyBytes, - this.getDelta(), Constants.NO_REPLY); - } else { - ByteUtils.setArguments(buf, 0, cmdBytes, this.keyBytes, - this.getDelta()); - } - this.ioBuffer = IoBuffer.wrap(buf); - } + @Override + public final void encode() { + byte[] cmdBytes = this.commandType == CommandType.INCR ? Constants.INCR : Constants.DECR; + int size = + 6 + this.keyBytes.length + ByteUtils.stringSize(this.getDelta()) + Constants.CRLF.length; + if (isNoreply()) { + size += 8; + } + byte[] buf = new byte[size]; + if (isNoreply()) { + ByteUtils.setArguments(buf, 0, cmdBytes, this.keyBytes, this.getDelta(), Constants.NO_REPLY); + } else { + ByteUtils.setArguments(buf, 0, cmdBytes, this.keyBytes, this.getDelta()); + } + this.ioBuffer = IoBuffer.wrap(buf); + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextQuitCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextQuitCommand.java index 9ed87f946..6c3b7d6e3 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextQuitCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextQuitCommand.java @@ -1,33 +1,25 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.text; import java.nio.ByteBuffer; - import net.rubyeye.xmemcached.command.Command; import net.rubyeye.xmemcached.command.CommandType; import net.rubyeye.xmemcached.impl.MemcachedTCPSession; - import com.google.code.yanf4j.buffer.IoBuffer; /** @@ -37,23 +29,22 @@ * */ public class TextQuitCommand extends Command { - public TextQuitCommand() { - super("quit", (byte[]) null, null); - commandType = CommandType.QUIT; - } - - static final IoBuffer QUIT = IoBuffer.wrap("quit\r\n".getBytes()); - - @Override - public final boolean decode(MemcachedTCPSession session, - ByteBuffer buffer) { - // do nothing - return true; - } - - @Override - public final void encode() { - ioBuffer = QUIT.slice(); - } + public TextQuitCommand() { + super("quit", (byte[]) null, null); + commandType = CommandType.QUIT; + } + + static final IoBuffer QUIT = IoBuffer.wrap("quit\r\n".getBytes()); + + @Override + public final boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { + // do nothing + return true; + } + + @Override + public final void encode() { + ioBuffer = QUIT.slice(); + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextStatsCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextStatsCommand.java index de4fcad2a..21c9951a3 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextStatsCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextStatsCommand.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.text; @@ -27,14 +21,12 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.Command; import net.rubyeye.xmemcached.command.CommandType; import net.rubyeye.xmemcached.command.ServerAddressAware; import net.rubyeye.xmemcached.impl.MemcachedTCPSession; import net.rubyeye.xmemcached.networking.MemcachedSession; import net.rubyeye.xmemcached.utils.ByteUtils; - import com.google.code.yanf4j.buffer.IoBuffer; /** @@ -44,71 +36,67 @@ * */ public class TextStatsCommand extends Command implements ServerAddressAware { - public static final ByteBuffer STATS = ByteBuffer - .wrap("stats\r\n".getBytes()); - private InetSocketAddress server; - private String itemName; + public static final ByteBuffer STATS = ByteBuffer.wrap("stats\r\n".getBytes()); + private InetSocketAddress server; + private String itemName; - public String getItemName() { - return this.itemName; - } + public String getItemName() { + return this.itemName; + } - public final InetSocketAddress getServer() { - return this.server; - } + public final InetSocketAddress getServer() { + return this.server; + } - public final void setServer(InetSocketAddress server) { - this.server = server; - } + public final void setServer(InetSocketAddress server) { + this.server = server; + } - public void setItemName(String item) { - this.itemName = item; - } + public void setItemName(String item) { + this.itemName = item; + } - public TextStatsCommand(InetSocketAddress server, CountDownLatch latch, - String itemName) { - super("stats", (byte[]) null, latch); - this.commandType = CommandType.STATS; - this.server = server; - this.itemName = itemName; - this.result = new HashMap(); + public TextStatsCommand(InetSocketAddress server, CountDownLatch latch, String itemName) { + super("stats", (byte[]) null, latch); + this.commandType = CommandType.STATS; + this.server = server; + this.itemName = itemName; + this.result = new HashMap(); - } + } - @Override - @SuppressWarnings("unchecked") - public final boolean decode(MemcachedTCPSession session, - ByteBuffer buffer) { - String line = null; - while ((line = ByteUtils.nextLine(buffer)) != null) { - if (line.equals("END")) { // at the end - return done(session); - } else if (line.startsWith("STAT") || line.startsWith("PREFIX") - || line.startsWith("ITEM")) { - // Fixed issue 126 - String[] items = line.split(" "); - ((Map) getResult()).put(items[1], items[2]); - } else { - return decodeError(line); - } - } - return false; - } + @Override + @SuppressWarnings("unchecked") + public final boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { + String line = null; + while ((line = ByteUtils.nextLine(buffer)) != null) { + if (line.equals("END")) { // at the end + return done(session); + } else if (line.startsWith("STAT") || line.startsWith("PREFIX") || line.startsWith("ITEM")) { + // Fixed issue 126 + String[] items = line.split(" "); + ((Map) getResult()).put(items[1], items[2]); + } else { + return decodeError(line); + } + } + return false; + } - private final boolean done(MemcachedSession session) { - countDownLatch(); - return true; - } + private final boolean done(MemcachedSession session) { + countDownLatch(); + return true; + } - @Override - public final void encode() { - if (this.itemName == null) { - this.ioBuffer = IoBuffer.wrap(STATS.slice()); - } else { - this.ioBuffer = IoBuffer.allocate(5 + this.itemName.length() + 3); - ByteUtils.setArguments(this.ioBuffer, "stats", this.itemName); - this.ioBuffer.flip(); - } - } + @Override + public final void encode() { + if (this.itemName == null) { + this.ioBuffer = IoBuffer.wrap(STATS.slice()); + } else { + this.ioBuffer = IoBuffer.allocate(5 + this.itemName.length() + 3); + ByteUtils.setArguments(this.ioBuffer, "stats", this.itemName); + this.ioBuffer.flip(); + } + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextStoreCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextStoreCommand.java index 0f42c0d4f..b8aad0161 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextStoreCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextStoreCommand.java @@ -1,30 +1,23 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.text; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.Command; import net.rubyeye.xmemcached.command.CommandType; import net.rubyeye.xmemcached.command.StoreCommand; @@ -33,7 +26,6 @@ import net.rubyeye.xmemcached.transcoders.CachedData; import net.rubyeye.xmemcached.transcoders.Transcoder; import net.rubyeye.xmemcached.utils.ByteUtils; - import com.google.code.yanf4j.buffer.IoBuffer; /** @@ -43,161 +35,155 @@ * */ public class TextStoreCommand extends Command implements StoreCommand { - protected int expTime; - protected long cas; - protected Object value; - - @SuppressWarnings("unchecked") - public TextStoreCommand(String key, byte[] keyBytes, CommandType cmdType, - CountDownLatch latch, int exp, long cas, Object value, - boolean noreply, Transcoder transcoder) { - super(key, keyBytes, cmdType, latch); - this.expTime = exp; - this.cas = cas; - this.value = value; - this.noreply = noreply; - this.transcoder = transcoder; - } - - public final int getExpTime() { - return this.expTime; - } - - public final void setExpTime(int exp) { - this.expTime = exp; - } - - public final long getCas() { - return this.cas; - } - - public final void setCas(long cas) { - this.cas = cas; - } - - public final Object getValue() { - return this.value; - } - - public final void setValue(Object value) { - this.value = value; - } - - @Override - @SuppressWarnings("unchecked") - public final Transcoder getTranscoder() { - return this.transcoder; - } - - @Override - @SuppressWarnings("unchecked") - public final void setTranscoder(Transcoder transcoder) { - this.transcoder = transcoder; - } - - @Override - public boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { - if (buffer == null || !buffer.hasRemaining()) { - return false; - } - if (this.result == null) { - if (buffer.remaining() < 2) - return false; - int pos = buffer.position(); - byte first = buffer.get(pos); - byte second = buffer.get(pos + 1); - if (first == 'S' && second == 'T') { - setResult(Boolean.TRUE); - countDownLatch(); - // STORED\r\n - return ByteUtils.stepBuffer(buffer, 8); - } else if (first == 'N') { - setResult(Boolean.FALSE); - countDownLatch(); - // NOT_STORED\r\n - return ByteUtils.stepBuffer(buffer, 12); - } else { - return decodeError(session, buffer); - } - } else { - Boolean result = (Boolean) this.result; - if (result) { - return ByteUtils.stepBuffer(buffer, 8); - } else { - return ByteUtils.stepBuffer(buffer, 12); - } - } - } - - private String getCommandName() { - switch (this.commandType) { - case ADD : - return "add"; - case SET : - return "set"; - case REPLACE : - return "replace"; - case APPEND : - return "append"; - case PREPEND : - return "prepend"; - case CAS : - return "cas"; - default : - throw new IllegalArgumentException( - this.commandType.name() + " is not a store command"); - - } - } - - @Override - public final void encode() { - final CachedData data = encodeValue(); - String cmdStr = getCommandName(); - byte[] encodedData = data.getData(); - int flag = data.getFlag(); - int size = cmdStr.length() + this.keyBytes.length - + ByteUtils.stringSize(flag) - + ByteUtils.stringSize(this.expTime) + encodedData.length - + ByteUtils.stringSize(encodedData.length) + 8; - if (this.commandType == CommandType.CAS) { - size += 1 + ByteUtils.stringSize(this.cas); - } - byte[] buf; - if (isNoreply()) { - buf = new byte[size + 8]; - } else { - buf = new byte[size]; - } - int offset = 0; - if (this.commandType == CommandType.CAS) { - if (isNoreply()) { - offset = ByteUtils.setArguments(buf, offset, cmdStr, - this.keyBytes, flag, this.expTime, encodedData.length, - this.cas, Constants.NO_REPLY); - } else { - offset = ByteUtils.setArguments(buf, offset, cmdStr, - this.keyBytes, flag, this.expTime, encodedData.length, - this.cas); - } - } else { - if (isNoreply()) { - offset = ByteUtils.setArguments(buf, offset, cmdStr, - this.keyBytes, flag, this.expTime, encodedData.length, - Constants.NO_REPLY); - } else { - offset = ByteUtils.setArguments(buf, offset, cmdStr, - this.keyBytes, flag, this.expTime, encodedData.length); - } - } - ByteUtils.setArguments(buf, offset, encodedData); - this.ioBuffer = IoBuffer.wrap(buf); - } - - @SuppressWarnings("unchecked") - protected CachedData encodeValue() { - final CachedData data = this.transcoder.encode(this.value); - return data; - } + protected int expTime; + protected long cas; + protected Object value; + + @SuppressWarnings("unchecked") + public TextStoreCommand(String key, byte[] keyBytes, CommandType cmdType, CountDownLatch latch, + int exp, long cas, Object value, boolean noreply, Transcoder transcoder) { + super(key, keyBytes, cmdType, latch); + this.expTime = exp; + this.cas = cas; + this.value = value; + this.noreply = noreply; + this.transcoder = transcoder; + } + + public final int getExpTime() { + return this.expTime; + } + + public final void setExpTime(int exp) { + this.expTime = exp; + } + + public final long getCas() { + return this.cas; + } + + public final void setCas(long cas) { + this.cas = cas; + } + + public final Object getValue() { + return this.value; + } + + public final void setValue(Object value) { + this.value = value; + } + + @Override + @SuppressWarnings("unchecked") + public final Transcoder getTranscoder() { + return this.transcoder; + } + + @Override + @SuppressWarnings("unchecked") + public final void setTranscoder(Transcoder transcoder) { + this.transcoder = transcoder; + } + + @Override + public boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { + if (buffer == null || !buffer.hasRemaining()) { + return false; + } + if (this.result == null) { + if (buffer.remaining() < 2) + return false; + int pos = buffer.position(); + byte first = buffer.get(pos); + byte second = buffer.get(pos + 1); + if (first == 'S' && second == 'T') { + setResult(Boolean.TRUE); + countDownLatch(); + // STORED\r\n + return ByteUtils.stepBuffer(buffer, 8); + } else if (first == 'N') { + setResult(Boolean.FALSE); + countDownLatch(); + // NOT_STORED\r\n + return ByteUtils.stepBuffer(buffer, 12); + } else { + return decodeError(session, buffer); + } + } else { + Boolean result = (Boolean) this.result; + if (result) { + return ByteUtils.stepBuffer(buffer, 8); + } else { + return ByteUtils.stepBuffer(buffer, 12); + } + } + } + + private String getCommandName() { + switch (this.commandType) { + case ADD: + return "add"; + case SET: + return "set"; + case REPLACE: + return "replace"; + case APPEND: + return "append"; + case PREPEND: + return "prepend"; + case CAS: + return "cas"; + default: + throw new IllegalArgumentException(this.commandType.name() + " is not a store command"); + + } + } + + @Override + public final void encode() { + final CachedData data = encodeValue(); + String cmdStr = getCommandName(); + byte[] encodedData = data.getData(); + int flag = data.getFlag(); + int size = cmdStr.length() + this.keyBytes.length + ByteUtils.stringSize(flag) + + ByteUtils.stringSize(this.expTime) + encodedData.length + + ByteUtils.stringSize(encodedData.length) + 8; + if (this.commandType == CommandType.CAS) { + size += 1 + ByteUtils.stringSize(this.cas); + } + byte[] buf; + if (isNoreply()) { + buf = new byte[size + 8]; + } else { + buf = new byte[size]; + } + int offset = 0; + if (this.commandType == CommandType.CAS) { + if (isNoreply()) { + offset = ByteUtils.setArguments(buf, offset, cmdStr, this.keyBytes, flag, this.expTime, + encodedData.length, this.cas, Constants.NO_REPLY); + } else { + offset = ByteUtils.setArguments(buf, offset, cmdStr, this.keyBytes, flag, this.expTime, + encodedData.length, this.cas); + } + } else { + if (isNoreply()) { + offset = ByteUtils.setArguments(buf, offset, cmdStr, this.keyBytes, flag, this.expTime, + encodedData.length, Constants.NO_REPLY); + } else { + offset = ByteUtils.setArguments(buf, offset, cmdStr, this.keyBytes, flag, this.expTime, + encodedData.length); + } + } + ByteUtils.setArguments(buf, offset, encodedData); + this.ioBuffer = IoBuffer.wrap(buf); + } + + @SuppressWarnings("unchecked") + protected CachedData encodeValue() { + final CachedData data = this.transcoder.encode(this.value); + return data; + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextTouchCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextTouchCommand.java index 895d63c16..a374c0069 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextTouchCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextTouchCommand.java @@ -1,36 +1,28 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.text; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.Command; import net.rubyeye.xmemcached.command.CommandType; import net.rubyeye.xmemcached.impl.MemcachedTCPSession; import net.rubyeye.xmemcached.monitor.Constants; import net.rubyeye.xmemcached.utils.ByteUtils; - import com.google.code.yanf4j.buffer.IoBuffer; /** @@ -42,75 +34,72 @@ */ public class TextTouchCommand extends Command { - private static final String NOT_FOUND = "NOT_FOUND\r\n"; - private static final String TOUCHED = "TOUCHED\r\n"; - private int expTime; + private static final String NOT_FOUND = "NOT_FOUND\r\n"; + private static final String TOUCHED = "TOUCHED\r\n"; + private int expTime; - public TextTouchCommand(String key, byte[] keyBytes, CommandType cmdType, - CountDownLatch latch, int expTime, boolean noreply) { - super(key, keyBytes, cmdType, latch); - this.expTime = expTime; - this.noreply = noreply; - } + public TextTouchCommand(String key, byte[] keyBytes, CommandType cmdType, CountDownLatch latch, + int expTime, boolean noreply) { + super(key, keyBytes, cmdType, latch); + this.expTime = expTime; + this.noreply = noreply; + } - public int getExpTime() { - return expTime; - } + public int getExpTime() { + return expTime; + } - public void setExpTime(int expTime) { - this.expTime = expTime; - } + public void setExpTime(int expTime) { + this.expTime = expTime; + } - @Override - public final boolean decode(MemcachedTCPSession session, - ByteBuffer buffer) { - if (buffer == null || !buffer.hasRemaining()) { - return false; - } - if (this.result == null) { - if (buffer.remaining() < 1) - return false; - byte first = buffer.get(buffer.position()); - if (first == 'T') { - setResult(Boolean.TRUE); - countDownLatch(); - // TOUCHED\r\n - return ByteUtils.stepBuffer(buffer, TOUCHED.length()); - } else if (first == 'N') { - setResult(Boolean.FALSE); - countDownLatch(); - // NOT_FOUND\r\n - return ByteUtils.stepBuffer(buffer, NOT_FOUND.length()); - } else { - return decodeError(session, buffer); - } - } else { - Boolean result = (Boolean) this.result; - if (result) { - return ByteUtils.stepBuffer(buffer, TOUCHED.length()); - } else { - return ByteUtils.stepBuffer(buffer, NOT_FOUND.length()); - } - } - } + @Override + public final boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { + if (buffer == null || !buffer.hasRemaining()) { + return false; + } + if (this.result == null) { + if (buffer.remaining() < 1) + return false; + byte first = buffer.get(buffer.position()); + if (first == 'T') { + setResult(Boolean.TRUE); + countDownLatch(); + // TOUCHED\r\n + return ByteUtils.stepBuffer(buffer, TOUCHED.length()); + } else if (first == 'N') { + setResult(Boolean.FALSE); + countDownLatch(); + // NOT_FOUND\r\n + return ByteUtils.stepBuffer(buffer, NOT_FOUND.length()); + } else { + return decodeError(session, buffer); + } + } else { + Boolean result = (Boolean) this.result; + if (result) { + return ByteUtils.stepBuffer(buffer, TOUCHED.length()); + } else { + return ByteUtils.stepBuffer(buffer, NOT_FOUND.length()); + } + } + } - @Override - public final void encode() { - byte[] cmdBytes = Constants.TOUCH; - int size = 7 + this.keyBytes.length + ByteUtils.stringSize(this.expTime) - + Constants.CRLF.length; - if (isNoreply()) { - size += 8; - } - byte[] buf = new byte[size]; - if (isNoreply()) { - ByteUtils.setArguments(buf, 0, cmdBytes, this.keyBytes, - this.expTime, Constants.NO_REPLY); - } else { - ByteUtils.setArguments(buf, 0, cmdBytes, this.keyBytes, - this.expTime); - } - this.ioBuffer = IoBuffer.wrap(buf); - } + @Override + public final void encode() { + byte[] cmdBytes = Constants.TOUCH; + int size = + 7 + this.keyBytes.length + ByteUtils.stringSize(this.expTime) + Constants.CRLF.length; + if (isNoreply()) { + size += 8; + } + byte[] buf = new byte[size]; + if (isNoreply()) { + ByteUtils.setArguments(buf, 0, cmdBytes, this.keyBytes, this.expTime, Constants.NO_REPLY); + } else { + ByteUtils.setArguments(buf, 0, cmdBytes, this.keyBytes, this.expTime); + } + this.ioBuffer = IoBuffer.wrap(buf); + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextVerbosityCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextVerbosityCommand.java index e4cf27fa0..8eb0424c8 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextVerbosityCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextVerbosityCommand.java @@ -1,35 +1,27 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.text; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.VerbosityCommand; import net.rubyeye.xmemcached.impl.MemcachedTCPSession; import net.rubyeye.xmemcached.monitor.Constants; import net.rubyeye.xmemcached.utils.ByteUtils; - import com.google.code.yanf4j.buffer.IoBuffer; /** @@ -40,49 +32,45 @@ */ public class TextVerbosityCommand extends VerbosityCommand { - public static final String VERBOSITY = "verbosity"; + public static final String VERBOSITY = "verbosity"; - public TextVerbosityCommand(CountDownLatch latch, int level, - boolean noreply) { - super(latch, level, noreply); + public TextVerbosityCommand(CountDownLatch latch, int level, boolean noreply) { + super(latch, level, noreply); - } + } - @Override - public boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { - if (buffer == null || !buffer.hasRemaining()) { - return false; - } - if (this.result == null) { - byte first = buffer.get(buffer.position()); - if (first == 'O') { - setResult(Boolean.TRUE); - countDownLatch(); - // OK\r\n - return ByteUtils.stepBuffer(buffer, 4); - } else { - return decodeError(session, buffer); - } - } else { - return ByteUtils.stepBuffer(buffer, 4); - } - } + @Override + public boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { + if (buffer == null || !buffer.hasRemaining()) { + return false; + } + if (this.result == null) { + byte first = buffer.get(buffer.position()); + if (first == 'O') { + setResult(Boolean.TRUE); + countDownLatch(); + // OK\r\n + return ByteUtils.stepBuffer(buffer, 4); + } else { + return decodeError(session, buffer); + } + } else { + return ByteUtils.stepBuffer(buffer, 4); + } + } - @Override - public void encode() { - final byte[] levelBytes = ByteUtils - .getBytes(String.valueOf(this.level)); - if (isNoreply()) { - this.ioBuffer = IoBuffer.allocate(4 + VERBOSITY.length() - + levelBytes.length + Constants.NO_REPLY.length); - ByteUtils.setArguments(this.ioBuffer, VERBOSITY, levelBytes, - Constants.NO_REPLY); - } else { - this.ioBuffer = IoBuffer - .allocate(2 + 1 + VERBOSITY.length() + levelBytes.length); - ByteUtils.setArguments(this.ioBuffer, VERBOSITY, levelBytes); + @Override + public void encode() { + final byte[] levelBytes = ByteUtils.getBytes(String.valueOf(this.level)); + if (isNoreply()) { + this.ioBuffer = + IoBuffer.allocate(4 + VERBOSITY.length() + levelBytes.length + Constants.NO_REPLY.length); + ByteUtils.setArguments(this.ioBuffer, VERBOSITY, levelBytes, Constants.NO_REPLY); + } else { + this.ioBuffer = IoBuffer.allocate(2 + 1 + VERBOSITY.length() + levelBytes.length); + ByteUtils.setArguments(this.ioBuffer, VERBOSITY, levelBytes); - } - this.ioBuffer.flip(); - } + } + this.ioBuffer.flip(); + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/TextVersionCommand.java b/src/main/java/net/rubyeye/xmemcached/command/text/TextVersionCommand.java index ccf4f4509..5679a3382 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/TextVersionCommand.java +++ b/src/main/java/net/rubyeye/xmemcached/command/text/TextVersionCommand.java @@ -1,37 +1,29 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.command.text; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; - import net.rubyeye.xmemcached.command.Command; import net.rubyeye.xmemcached.command.CommandType; import net.rubyeye.xmemcached.command.ServerAddressAware; import net.rubyeye.xmemcached.impl.MemcachedTCPSession; import net.rubyeye.xmemcached.utils.ByteUtils; - import com.google.code.yanf4j.buffer.IoBuffer; /** @@ -41,43 +33,41 @@ * */ public class TextVersionCommand extends Command implements ServerAddressAware { - public InetSocketAddress server; + public InetSocketAddress server; - public final InetSocketAddress getServer() { - return this.server; - } + public final InetSocketAddress getServer() { + return this.server; + } - public final void setServer(InetSocketAddress server) { - this.server = server; - } + public final void setServer(InetSocketAddress server) { + this.server = server; + } - public TextVersionCommand(final CountDownLatch latch, - InetSocketAddress server) { - super("[version]", (byte[]) null, latch); - this.commandType = CommandType.VERSION; - this.server = server; - } + public TextVersionCommand(final CountDownLatch latch, InetSocketAddress server) { + super("[version]", (byte[]) null, latch); + this.commandType = CommandType.VERSION; + this.server = server; + } - @Override - public final boolean decode(MemcachedTCPSession session, - ByteBuffer buffer) { - String line = ByteUtils.nextLine(buffer); - if (line != null) { - if (line.startsWith("VERSION")) { - String[] items = line.split(" "); - setResult(items.length > 1 ? items[1] : "unknown version"); - countDownLatch(); - return true; - } else { - return decodeError(line); - } - } - return false; - } + @Override + public final boolean decode(MemcachedTCPSession session, ByteBuffer buffer) { + String line = ByteUtils.nextLine(buffer); + if (line != null) { + if (line.startsWith("VERSION")) { + String[] items = line.split(" "); + setResult(items.length > 1 ? items[1] : "unknown version"); + countDownLatch(); + return true; + } else { + return decodeError(line); + } + } + return false; + } - @Override - public final void encode() { - this.ioBuffer = IoBuffer.wrap(VERSION.slice()); - } + @Override + public final void encode() { + this.ioBuffer = IoBuffer.wrap(VERSION.slice()); + } } diff --git a/src/main/java/net/rubyeye/xmemcached/command/text/package.html b/src/main/java/net/rubyeye/xmemcached/command/text/package.html index 70072ec08..743d1c92d 100644 --- a/src/main/java/net/rubyeye/xmemcached/command/text/package.html +++ b/src/main/java/net/rubyeye/xmemcached/command/text/package.html @@ -1,14 +1,10 @@ - - + - -Memcached text protocol implementations - - - -

Memcached text protocol implementations

- - - + + Memcached text protocol implementations + + +

Memcached text protocol implementations

+ + \ No newline at end of file diff --git a/src/main/java/net/rubyeye/xmemcached/exception/MemcachedClientException.java b/src/main/java/net/rubyeye/xmemcached/exception/MemcachedClientException.java index 0fcccc846..0dcfc6397 100644 --- a/src/main/java/net/rubyeye/xmemcached/exception/MemcachedClientException.java +++ b/src/main/java/net/rubyeye/xmemcached/exception/MemcachedClientException.java @@ -1,38 +1,36 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.exception; + /** * Memcached Client Exception * * @author dennis - * + * */ public class MemcachedClientException extends MemcachedException { - public MemcachedClientException() { - super(); - } + public MemcachedClientException() { + super(); + } - public MemcachedClientException(String s) { - super(s); - } + public MemcachedClientException(String s) { + super(s); + } - public MemcachedClientException(String message, Throwable cause) { - super(message, cause); - } + public MemcachedClientException(String message, Throwable cause) { + super(message, cause); + } - public MemcachedClientException(Throwable cause) { - super(cause); - } + public MemcachedClientException(Throwable cause) { + super(cause); + } - private static final long serialVersionUID = -236562546568164115L; + private static final long serialVersionUID = -236562546568164115L; } diff --git a/src/main/java/net/rubyeye/xmemcached/exception/MemcachedDecodeException.java b/src/main/java/net/rubyeye/xmemcached/exception/MemcachedDecodeException.java index 021c78327..9d7a1f538 100644 --- a/src/main/java/net/rubyeye/xmemcached/exception/MemcachedDecodeException.java +++ b/src/main/java/net/rubyeye/xmemcached/exception/MemcachedDecodeException.java @@ -8,22 +8,22 @@ */ public class MemcachedDecodeException extends RuntimeException { - public MemcachedDecodeException() { - super(); - } + public MemcachedDecodeException() { + super(); + } - public MemcachedDecodeException(String s) { - super(s); - } + public MemcachedDecodeException(String s) { + super(s); + } - public MemcachedDecodeException(String message, Throwable cause) { - super(message, cause); - } + public MemcachedDecodeException(String message, Throwable cause) { + super(message, cause); + } - public MemcachedDecodeException(Throwable cause) { - super(cause); - } + public MemcachedDecodeException(Throwable cause) { + super(cause); + } - private static final long serialVersionUID = 939539859359568164L; + private static final long serialVersionUID = 939539859359568164L; } diff --git a/src/main/java/net/rubyeye/xmemcached/exception/MemcachedException.java b/src/main/java/net/rubyeye/xmemcached/exception/MemcachedException.java index 4512d6bc2..f98962487 100644 --- a/src/main/java/net/rubyeye/xmemcached/exception/MemcachedException.java +++ b/src/main/java/net/rubyeye/xmemcached/exception/MemcachedException.java @@ -1,13 +1,10 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.exception; @@ -19,21 +16,21 @@ */ public class MemcachedException extends Exception { - public MemcachedException() { - super(); - } + public MemcachedException() { + super(); + } - public MemcachedException(String s) { - super(s); - } + public MemcachedException(String s) { + super(s); + } - public MemcachedException(String message, Throwable cause) { - super(message, cause); - } + public MemcachedException(String message, Throwable cause) { + super(message, cause); + } - public MemcachedException(Throwable cause) { - super(cause); - } + public MemcachedException(Throwable cause) { + super(cause); + } - private static final long serialVersionUID = -136568012546568164L; + private static final long serialVersionUID = -136568012546568164L; } diff --git a/src/main/java/net/rubyeye/xmemcached/exception/MemcachedServerException.java b/src/main/java/net/rubyeye/xmemcached/exception/MemcachedServerException.java index dae901484..f001a67b8 100644 --- a/src/main/java/net/rubyeye/xmemcached/exception/MemcachedServerException.java +++ b/src/main/java/net/rubyeye/xmemcached/exception/MemcachedServerException.java @@ -1,38 +1,36 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.exception; + /** * Memcached server exception * * @author dennis - * + * */ public class MemcachedServerException extends MemcachedException { - public MemcachedServerException() { - super(); - } + public MemcachedServerException() { + super(); + } - public MemcachedServerException(String s) { - super(s); - } + public MemcachedServerException(String s) { + super(s); + } - public MemcachedServerException(String message, Throwable cause) { - super(message, cause); - } + public MemcachedServerException(String message, Throwable cause) { + super(message, cause); + } - public MemcachedServerException(Throwable cause) { - super(cause); - } + public MemcachedServerException(Throwable cause) { + super(cause); + } - private static final long serialVersionUID = -236562546568164115L; + private static final long serialVersionUID = -236562546568164115L; } diff --git a/src/main/java/net/rubyeye/xmemcached/exception/NoValueException.java b/src/main/java/net/rubyeye/xmemcached/exception/NoValueException.java index ead18d788..b31823da1 100644 --- a/src/main/java/net/rubyeye/xmemcached/exception/NoValueException.java +++ b/src/main/java/net/rubyeye/xmemcached/exception/NoValueException.java @@ -1,39 +1,36 @@ -/** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 net.rubyeye.xmemcached.exception; - -/** - * Memcached Client Exception - * - * @author bmahe - * - */ -public class NoValueException extends MemcachedClientException { - - public NoValueException() { - super(); - } - - public NoValueException(String s) { - super(s); - } - - public NoValueException(String message, Throwable cause) { - super(message, cause); - } - - public NoValueException(Throwable cause) { - super(cause); - } - - private static final long serialVersionUID = -8717259791309127913L; -} +/** + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.exception; + +/** + * Memcached Client Exception + * + * @author bmahe + * + */ +public class NoValueException extends MemcachedClientException { + + public NoValueException() { + super(); + } + + public NoValueException(String s) { + super(s); + } + + public NoValueException(String message, Throwable cause) { + super(message, cause); + } + + public NoValueException(Throwable cause) { + super(cause); + } + + private static final long serialVersionUID = -8717259791309127913L; +} diff --git a/src/main/java/net/rubyeye/xmemcached/exception/UnknownCommandException.java b/src/main/java/net/rubyeye/xmemcached/exception/UnknownCommandException.java index c2ade274f..5ce538328 100644 --- a/src/main/java/net/rubyeye/xmemcached/exception/UnknownCommandException.java +++ b/src/main/java/net/rubyeye/xmemcached/exception/UnknownCommandException.java @@ -1,13 +1,10 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.exception; @@ -19,21 +16,21 @@ */ public class UnknownCommandException extends RuntimeException { - public UnknownCommandException() { - super(); - } + public UnknownCommandException() { + super(); + } - public UnknownCommandException(String s) { - super(s); - } + public UnknownCommandException(String s) { + super(s); + } - public UnknownCommandException(String message, Throwable cause) { - super(message, cause); - } + public UnknownCommandException(String message, Throwable cause) { + super(message, cause); + } - public UnknownCommandException(Throwable cause) { - super(cause); - } + public UnknownCommandException(Throwable cause) { + super(cause); + } - private static final long serialVersionUID = 8736625460917630395L; + private static final long serialVersionUID = 8736625460917630395L; } diff --git a/src/main/java/net/rubyeye/xmemcached/exception/package.html b/src/main/java/net/rubyeye/xmemcached/exception/package.html index 60231fbf3..1380e56ee 100644 --- a/src/main/java/net/rubyeye/xmemcached/exception/package.html +++ b/src/main/java/net/rubyeye/xmemcached/exception/package.html @@ -1,14 +1,10 @@ - - + - -XMemcached Exceptions - - - -

XMemcached Exceptions

- - - + + XMemcached Exceptions + + +

XMemcached Exceptions

+ + \ No newline at end of file diff --git a/src/main/java/net/rubyeye/xmemcached/impl/AbstractMemcachedSessionLocator.java b/src/main/java/net/rubyeye/xmemcached/impl/AbstractMemcachedSessionLocator.java index 6ace894bd..58b666b57 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/AbstractMemcachedSessionLocator.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/AbstractMemcachedSessionLocator.java @@ -1,22 +1,20 @@ -package net.rubyeye.xmemcached.impl; - -import net.rubyeye.xmemcached.MemcachedSessionLocator; - -/** - * Abstract session locator - * - * @author dennis - * @date 2010-12-25 - */ -public abstract class AbstractMemcachedSessionLocator - implements - MemcachedSessionLocator { - - protected boolean failureMode; - - public void setFailureMode(boolean failureMode) { - this.failureMode = failureMode; - - } - -} +package net.rubyeye.xmemcached.impl; + +import net.rubyeye.xmemcached.MemcachedSessionLocator; + +/** + * Abstract session locator + * + * @author dennis + * @date 2010-12-25 + */ +public abstract class AbstractMemcachedSessionLocator implements MemcachedSessionLocator { + + protected boolean failureMode; + + public void setFailureMode(boolean failureMode) { + this.failureMode = failureMode; + + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/impl/ArrayMemcachedSessionLocator.java b/src/main/java/net/rubyeye/xmemcached/impl/ArrayMemcachedSessionLocator.java index 1d91d025d..aed18fdd3 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/ArrayMemcachedSessionLocator.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/ArrayMemcachedSessionLocator.java @@ -1,13 +1,10 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.impl; @@ -16,10 +13,8 @@ import java.util.Collections; import java.util.List; import java.util.Random; - import net.rubyeye.xmemcached.HashAlgorithm; import net.rubyeye.xmemcached.networking.MemcachedSession; - import com.google.code.yanf4j.core.Session; /** @@ -28,120 +23,116 @@ * @author dennis * */ -public class ArrayMemcachedSessionLocator - extends - AbstractMemcachedSessionLocator { - - private HashAlgorithm hashAlgorighm; - private transient volatile List> sessions; - - public ArrayMemcachedSessionLocator() { - this.hashAlgorighm = HashAlgorithm.NATIVE_HASH; - } - - public ArrayMemcachedSessionLocator(HashAlgorithm hashAlgorighm) { - this.hashAlgorighm = hashAlgorighm; - } - - public final void setHashAlgorighm(HashAlgorithm hashAlgorighm) { - this.hashAlgorighm = hashAlgorighm; - } - - public final long getHash(int size, String key) { - long hash = this.hashAlgorighm.hash(key); - return hash % size; - } - - final Random rand = new Random(); - - public final Session getSessionByKey(final String key) { - if (this.sessions == null || this.sessions.size() == 0) { - return null; - } - // Copy on read - List> sessionList = this.sessions; - int size = sessionList.size(); - if (size == 0) { - return null; - } - long start = this.getHash(size, key); - List sessions = sessionList.get((int) start); - Session session = getRandomSession(sessions); - - // If it is not failure mode,get next available session - if (!this.failureMode && (session == null || session.isClosed())) { - long next = this.getNext(size, start); - while ((session == null || session.isClosed()) && next != start) { - sessions = sessionList.get((int) next); - next = this.getNext(size, next); - session = getRandomSession(sessions); - } - } - return session; - } - - private Session getRandomSession(List sessions) { - if (sessions == null || sessions.isEmpty()) - return null; - return sessions.get(rand.nextInt(sessions.size())); - } - - public final long getNext(int size, long start) { - if (start == size - 1) { - return 0; - } else { - return start + 1; - } - } - - public final void updateSessions(final Collection list) { - if (list == null || list.isEmpty()) { - this.sessions = Collections.emptyList(); - return; - } - Collection copySessions = list; - List> tmpList = new ArrayList>(); - Session target = null; - List subList = null; - for (Session session : copySessions) { - if (target == null) { - target = session; - subList = new ArrayList(); - subList.add(target); - } else { - if (session.getRemoteSocketAddress() - .equals(target.getRemoteSocketAddress())) { - subList.add(session); - } else { - tmpList.add(subList); - target = session; - subList = new ArrayList(); - subList.add(target); - } - } - } - - // The last one - if (subList != null) { - tmpList.add(subList); - } - - List> newSessions = new ArrayList>( - tmpList.size() * 2); - for (List sessions : tmpList) { - if (sessions != null && !sessions.isEmpty()) { - Session session = sessions.get(0); - if (session instanceof MemcachedTCPSession) { - int weight = ((MemcachedSession) session).getWeight(); - for (int i = 0; i < weight; i++) { - newSessions.add(sessions); - } - } else { - newSessions.add(sessions); - } - } - - } - this.sessions = newSessions; - } +public class ArrayMemcachedSessionLocator extends AbstractMemcachedSessionLocator { + + private HashAlgorithm hashAlgorighm; + private transient volatile List> sessions; + + public ArrayMemcachedSessionLocator() { + this.hashAlgorighm = HashAlgorithm.NATIVE_HASH; + } + + public ArrayMemcachedSessionLocator(HashAlgorithm hashAlgorighm) { + this.hashAlgorighm = hashAlgorighm; + } + + public final void setHashAlgorighm(HashAlgorithm hashAlgorighm) { + this.hashAlgorighm = hashAlgorighm; + } + + public final long getHash(int size, String key) { + long hash = this.hashAlgorighm.hash(key); + return hash % size; + } + + final Random rand = new Random(); + + public final Session getSessionByKey(final String key) { + if (this.sessions == null || this.sessions.size() == 0) { + return null; + } + // Copy on read + List> sessionList = this.sessions; + int size = sessionList.size(); + if (size == 0) { + return null; + } + long start = this.getHash(size, key); + List sessions = sessionList.get((int) start); + Session session = getRandomSession(sessions); + + // If it is not failure mode,get next available session + if (!this.failureMode && (session == null || session.isClosed())) { + long next = this.getNext(size, start); + while ((session == null || session.isClosed()) && next != start) { + sessions = sessionList.get((int) next); + next = this.getNext(size, next); + session = getRandomSession(sessions); + } + } + return session; + } + + private Session getRandomSession(List sessions) { + if (sessions == null || sessions.isEmpty()) + return null; + return sessions.get(rand.nextInt(sessions.size())); + } + + public final long getNext(int size, long start) { + if (start == size - 1) { + return 0; + } else { + return start + 1; + } + } + + public final void updateSessions(final Collection list) { + if (list == null || list.isEmpty()) { + this.sessions = Collections.emptyList(); + return; + } + Collection copySessions = list; + List> tmpList = new ArrayList>(); + Session target = null; + List subList = null; + for (Session session : copySessions) { + if (target == null) { + target = session; + subList = new ArrayList(); + subList.add(target); + } else { + if (session.getRemoteSocketAddress().equals(target.getRemoteSocketAddress())) { + subList.add(session); + } else { + tmpList.add(subList); + target = session; + subList = new ArrayList(); + subList.add(target); + } + } + } + + // The last one + if (subList != null) { + tmpList.add(subList); + } + + List> newSessions = new ArrayList>(tmpList.size() * 2); + for (List sessions : tmpList) { + if (sessions != null && !sessions.isEmpty()) { + Session session = sessions.get(0); + if (session instanceof MemcachedTCPSession) { + int weight = ((MemcachedSession) session).getWeight(); + for (int i = 0; i < weight; i++) { + newSessions.add(sessions); + } + } else { + newSessions.add(sessions); + } + } + + } + this.sessions = newSessions; + } } diff --git a/src/main/java/net/rubyeye/xmemcached/impl/ClosedMemcachedTCPSession.java b/src/main/java/net/rubyeye/xmemcached/impl/ClosedMemcachedTCPSession.java index 26e4741f2..ca51a3d3c 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/ClosedMemcachedTCPSession.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/ClosedMemcachedTCPSession.java @@ -1,230 +1,223 @@ -package net.rubyeye.xmemcached.impl; - -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.nio.ByteOrder; - -import net.rubyeye.xmemcached.buffer.BufferAllocator; -import net.rubyeye.xmemcached.networking.ClosedMemcachedSession; -import net.rubyeye.xmemcached.networking.MemcachedSession; -import net.rubyeye.xmemcached.utils.InetSocketAddressWrapper; - -import com.google.code.yanf4j.core.Handler; -import com.google.code.yanf4j.core.CodecFactory.Decoder; -import com.google.code.yanf4j.core.CodecFactory.Encoder; - -/** - * Closed session - * - * @author dennis - * - */ -public class ClosedMemcachedTCPSession - implements - ClosedMemcachedSession, - MemcachedSession { - private InetSocketAddressWrapper inetSocketAddressWrapper; - private volatile boolean allowReconnect = true; - private volatile boolean authFailed = false; - - public ClosedMemcachedTCPSession( - InetSocketAddressWrapper inetSocketAddressWrapper) { - super(); - this.inetSocketAddressWrapper = inetSocketAddressWrapper; - } - - public void setBufferAllocator(BufferAllocator allocator) { - - } - - public void destroy() { - - } - - public void quit() { - - } - - public boolean isAuthFailed() { - return authFailed; - } - - public void setAuthFailed(boolean authFailed) { - this.authFailed = authFailed; - - } - - public InetSocketAddressWrapper getInetSocketAddressWrapper() { - return this.inetSocketAddressWrapper; - } - - public int getOrder() { - return this.inetSocketAddressWrapper.getOrder(); - } - - public int getWeight() { - return this.inetSocketAddressWrapper.getWeight(); - } - - public boolean isAllowReconnect() { - return this.allowReconnect; - } - - public void setAllowReconnect(boolean allow) { - this.allowReconnect = allow; - } - - public void clearAttributes() { - - } - - public void close() { - - } - - public void flush() { - - } - - public Object getAttribute(String key) { - - return null; - } - - public Decoder getDecoder() { - - return null; - } - - public Encoder getEncoder() { - - return null; - } - - public Handler getHandler() { - - return null; - } - - public long getLastOperationTimeStamp() { - - return 0; - } - - public InetAddress getLocalAddress() { - - return null; - } - - public ByteOrder getReadBufferByteOrder() { - - return null; - } - - public InetSocketAddress getRemoteSocketAddress() { - return this.inetSocketAddressWrapper.getInetSocketAddress(); - } - - public long getScheduleWritenBytes() { - - return 0; - } - - public long getSessionIdleTimeout() { - - return 0; - } - - public long getSessionTimeout() { - - return 0; - } - - public boolean isClosed() { - return true; - } - - public boolean isExpired() { - - return false; - } - - public boolean isHandleReadWriteConcurrently() { - return true; - } - - public boolean isIdle() { - - return false; - } - - public boolean isLoopbackConnection() { - - return false; - } - - public boolean isUseBlockingRead() { - - return false; - } - - public boolean isUseBlockingWrite() { - - return false; - } - - public void removeAttribute(String key) { - - } - - public void setAttribute(String key, Object value) { - - } - - public Object setAttributeIfAbsent(String key, Object value) { - - return null; - } - - public void setDecoder(Decoder decoder) { - - } - - public void setEncoder(Encoder encoder) { - - } - - public void setHandleReadWriteConcurrently( - boolean handleReadWriteConcurrently) { - - } - - public void setReadBufferByteOrder(ByteOrder readBufferByteOrder) { - - } - - public void setSessionIdleTimeout(long sessionIdleTimeout) { - - } - - public void setSessionTimeout(long sessionTimeout) { - - } - - public void setUseBlockingRead(boolean useBlockingRead) { - - } - - public void setUseBlockingWrite(boolean useBlockingWrite) { - - } - - public void start() { - - } - - public void write(Object packet) { - - } - -} +package net.rubyeye.xmemcached.impl; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.nio.ByteOrder; +import net.rubyeye.xmemcached.buffer.BufferAllocator; +import net.rubyeye.xmemcached.networking.ClosedMemcachedSession; +import net.rubyeye.xmemcached.networking.MemcachedSession; +import net.rubyeye.xmemcached.utils.InetSocketAddressWrapper; +import com.google.code.yanf4j.core.Handler; +import com.google.code.yanf4j.core.CodecFactory.Decoder; +import com.google.code.yanf4j.core.CodecFactory.Encoder; + +/** + * Closed session + * + * @author dennis + * + */ +public class ClosedMemcachedTCPSession implements ClosedMemcachedSession, MemcachedSession { + private InetSocketAddressWrapper inetSocketAddressWrapper; + private volatile boolean allowReconnect = true; + private volatile boolean authFailed = false; + + public ClosedMemcachedTCPSession(InetSocketAddressWrapper inetSocketAddressWrapper) { + super(); + this.inetSocketAddressWrapper = inetSocketAddressWrapper; + } + + public void setBufferAllocator(BufferAllocator allocator) { + + } + + public void destroy() { + + } + + public void quit() { + + } + + public boolean isAuthFailed() { + return authFailed; + } + + public void setAuthFailed(boolean authFailed) { + this.authFailed = authFailed; + + } + + public InetSocketAddressWrapper getInetSocketAddressWrapper() { + return this.inetSocketAddressWrapper; + } + + public int getOrder() { + return this.inetSocketAddressWrapper.getOrder(); + } + + public int getWeight() { + return this.inetSocketAddressWrapper.getWeight(); + } + + public boolean isAllowReconnect() { + return this.allowReconnect; + } + + public void setAllowReconnect(boolean allow) { + this.allowReconnect = allow; + } + + public void clearAttributes() { + + } + + public void close() { + + } + + public void flush() { + + } + + public Object getAttribute(String key) { + + return null; + } + + public Decoder getDecoder() { + + return null; + } + + public Encoder getEncoder() { + + return null; + } + + public Handler getHandler() { + + return null; + } + + public long getLastOperationTimeStamp() { + + return 0; + } + + public InetAddress getLocalAddress() { + + return null; + } + + public ByteOrder getReadBufferByteOrder() { + + return null; + } + + public InetSocketAddress getRemoteSocketAddress() { + return this.inetSocketAddressWrapper.getInetSocketAddress(); + } + + public long getScheduleWritenBytes() { + + return 0; + } + + public long getSessionIdleTimeout() { + + return 0; + } + + public long getSessionTimeout() { + + return 0; + } + + public boolean isClosed() { + return true; + } + + public boolean isExpired() { + + return false; + } + + public boolean isHandleReadWriteConcurrently() { + return true; + } + + public boolean isIdle() { + + return false; + } + + public boolean isLoopbackConnection() { + + return false; + } + + public boolean isUseBlockingRead() { + + return false; + } + + public boolean isUseBlockingWrite() { + + return false; + } + + public void removeAttribute(String key) { + + } + + public void setAttribute(String key, Object value) { + + } + + public Object setAttributeIfAbsent(String key, Object value) { + + return null; + } + + public void setDecoder(Decoder decoder) { + + } + + public void setEncoder(Encoder encoder) { + + } + + public void setHandleReadWriteConcurrently(boolean handleReadWriteConcurrently) { + + } + + public void setReadBufferByteOrder(ByteOrder readBufferByteOrder) { + + } + + public void setSessionIdleTimeout(long sessionIdleTimeout) { + + } + + public void setSessionTimeout(long sessionTimeout) { + + } + + public void setUseBlockingRead(boolean useBlockingRead) { + + } + + public void setUseBlockingWrite(boolean useBlockingWrite) { + + } + + public void start() { + + } + + public void write(Object packet) { + + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/impl/ConnectFuture.java b/src/main/java/net/rubyeye/xmemcached/impl/ConnectFuture.java index 65762e3a1..55a638bbf 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/ConnectFuture.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/ConnectFuture.java @@ -1,29 +1,22 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.impl; import net.rubyeye.xmemcached.utils.InetSocketAddressWrapper; - import com.google.code.yanf4j.core.impl.FutureImpl; /** @@ -34,15 +27,15 @@ */ public class ConnectFuture extends FutureImpl { - private final InetSocketAddressWrapper inetSocketAddressWrapper; + private final InetSocketAddressWrapper inetSocketAddressWrapper; - public ConnectFuture(InetSocketAddressWrapper inetSocketAddressWrapper) { - super(); - this.inetSocketAddressWrapper = inetSocketAddressWrapper; - } + public ConnectFuture(InetSocketAddressWrapper inetSocketAddressWrapper) { + super(); + this.inetSocketAddressWrapper = inetSocketAddressWrapper; + } - public InetSocketAddressWrapper getInetSocketAddressWrapper() { - return this.inetSocketAddressWrapper; - } + public InetSocketAddressWrapper getInetSocketAddressWrapper() { + return this.inetSocketAddressWrapper; + } } diff --git a/src/main/java/net/rubyeye/xmemcached/impl/DefaultKeyProvider.java b/src/main/java/net/rubyeye/xmemcached/impl/DefaultKeyProvider.java index 671777b30..bb5dc2811 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/DefaultKeyProvider.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/DefaultKeyProvider.java @@ -1,19 +1,19 @@ -package net.rubyeye.xmemcached.impl; - -import net.rubyeye.xmemcached.KeyProvider; - -/** - * Default key provider,returns the key itself. - * - * @author dennis - * @since 1.3.8 - */ -public final class DefaultKeyProvider implements KeyProvider { - - public static final KeyProvider INSTANCE = new DefaultKeyProvider(); - - public final String process(String key) { - return key; - } - -} +package net.rubyeye.xmemcached.impl; + +import net.rubyeye.xmemcached.KeyProvider; + +/** + * Default key provider,returns the key itself. + * + * @author dennis + * @since 1.3.8 + */ +public final class DefaultKeyProvider implements KeyProvider { + + public static final KeyProvider INSTANCE = new DefaultKeyProvider(); + + public final String process(String key) { + return key; + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/impl/ElectionMemcachedSessionLocator.java b/src/main/java/net/rubyeye/xmemcached/impl/ElectionMemcachedSessionLocator.java index 969f5c931..7549693b4 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/ElectionMemcachedSessionLocator.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/ElectionMemcachedSessionLocator.java @@ -1,34 +1,26 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.impl; import java.util.ArrayList; import java.util.Collection; import java.util.List; - import net.rubyeye.xmemcached.HashAlgorithm; import net.rubyeye.xmemcached.networking.MemcachedSession; - import com.google.code.yanf4j.core.Session; /** @@ -37,67 +29,62 @@ * @author dennis * */ -public class ElectionMemcachedSessionLocator - extends - AbstractMemcachedSessionLocator { +public class ElectionMemcachedSessionLocator extends AbstractMemcachedSessionLocator { - private transient volatile List sessions; + private transient volatile List sessions; - private final HashAlgorithm hashAlgorithm; + private final HashAlgorithm hashAlgorithm; - public ElectionMemcachedSessionLocator() { - this.hashAlgorithm = HashAlgorithm.ELECTION_HASH; - } + public ElectionMemcachedSessionLocator() { + this.hashAlgorithm = HashAlgorithm.ELECTION_HASH; + } - public ElectionMemcachedSessionLocator(HashAlgorithm hashAlgorithm) { - super(); - this.hashAlgorithm = hashAlgorithm; - } + public ElectionMemcachedSessionLocator(HashAlgorithm hashAlgorithm) { + super(); + this.hashAlgorithm = hashAlgorithm; + } - public Session getSessionByKey(String key) { - // copy on write - List copySessionList = new ArrayList(this.sessions); - Session result = this.getSessionByElection(key, copySessionList); - while (!this.failureMode && (result == null || result.isClosed()) - && copySessionList.size() > 0) { - copySessionList.remove(result); - result = this.getSessionByElection(key, copySessionList); - } - return result; - } + public Session getSessionByKey(String key) { + // copy on write + List copySessionList = new ArrayList(this.sessions); + Session result = this.getSessionByElection(key, copySessionList); + while (!this.failureMode && (result == null || result.isClosed()) + && copySessionList.size() > 0) { + copySessionList.remove(result); + result = this.getSessionByElection(key, copySessionList); + } + return result; + } - private Session getSessionByElection(String key, - List copySessionList) { - Session result = null; - long highScore = 0; - for (Session session : copySessionList) { - long hash = 0; - if (session instanceof MemcachedTCPSession) { - MemcachedSession tcpSession = (MemcachedSession) session; - for (int i = 0; i < tcpSession.getWeight(); i++) { - hash = this.hashAlgorithm - .hash(session.getRemoteSocketAddress().toString() - + "-" + i + key); - if (hash > highScore) { - highScore = hash; - result = session; - } - } - } else { - hash = this.hashAlgorithm.hash( - session.getRemoteSocketAddress().toString() + key); + private Session getSessionByElection(String key, List copySessionList) { + Session result = null; + long highScore = 0; + for (Session session : copySessionList) { + long hash = 0; + if (session instanceof MemcachedTCPSession) { + MemcachedSession tcpSession = (MemcachedSession) session; + for (int i = 0; i < tcpSession.getWeight(); i++) { + hash = + this.hashAlgorithm.hash(session.getRemoteSocketAddress().toString() + "-" + i + key); + if (hash > highScore) { + highScore = hash; + result = session; + } + } + } else { + hash = this.hashAlgorithm.hash(session.getRemoteSocketAddress().toString() + key); - } - if (hash > highScore) { - highScore = hash; - result = session; - } - } - return result; - } + } + if (hash > highScore) { + highScore = hash; + result = session; + } + } + return result; + } - public void updateSessions(Collection list) { - this.sessions = new ArrayList(list); - } + public void updateSessions(Collection list) { + this.sessions = new ArrayList(list); + } } diff --git a/src/main/java/net/rubyeye/xmemcached/impl/FlowControlLinkedTransferQueue.java b/src/main/java/net/rubyeye/xmemcached/impl/FlowControlLinkedTransferQueue.java index 69548a17c..d9c8cc839 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/FlowControlLinkedTransferQueue.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/FlowControlLinkedTransferQueue.java @@ -1,163 +1,156 @@ -package net.rubyeye.xmemcached.impl; - -import java.util.Collection; -import java.util.Iterator; -import java.util.concurrent.TimeUnit; - -import net.rubyeye.xmemcached.FlowControl; -import net.rubyeye.xmemcached.command.Command; - -import com.google.code.yanf4j.core.WriteMessage; -import com.google.code.yanf4j.util.LinkedTransferQueue; - -public class FlowControlLinkedTransferQueue - extends - LinkedTransferQueue { - private FlowControl flowControl; - - public FlowControlLinkedTransferQueue(FlowControl flowControl) { - super(); - this.flowControl = flowControl; - } - - private void checkPermits(WriteMessage e) { - if (e.getMessage() instanceof Command) { - Command cmd = (Command) e.getMessage(); - if (cmd.isNoreply()) { - int i = 3; - boolean success = false; - while (i-- > 0) { - if (this.flowControl.aquire()) { - success = true; - break; - } else { - // reduce consuming cpu - Thread.yield(); - } - } - if (!success) - throw new IllegalStateException( - "No permit for noreply operation,max=" - + flowControl.max()); - } - } - } - - @Override - public void put(WriteMessage e) throws InterruptedException { - checkPermits(e); - super.put(e); - } - - @Override - public boolean offer(WriteMessage e, long timeout, TimeUnit unit) - throws InterruptedException { - checkPermits(e); - return super.offer(e, timeout, unit); - } - - @Override - public boolean offer(WriteMessage e) { - checkPermits(e); - return super.offer(e); - } - - @Override - public void transfer(WriteMessage e) throws InterruptedException { - checkPermits(e); - super.transfer(e); - } - - @Override - public boolean tryTransfer(WriteMessage e, long timeout, TimeUnit unit) - throws InterruptedException { - checkPermits(e); - return super.tryTransfer(e, timeout, unit); - } - - @Override - public boolean tryTransfer(WriteMessage e) { - checkPermits(e); - return super.tryTransfer(e); - } - - @Override - public WriteMessage take() throws InterruptedException { - WriteMessage rt = super.take(); - releasePermit(rt); - return rt; - } - - @Override - public WriteMessage poll(long timeout, TimeUnit unit) - throws InterruptedException { - WriteMessage rt = super.poll(timeout, unit); - releasePermit(rt); - return rt; - } - - @Override - public WriteMessage poll() { - WriteMessage rt = super.poll(); - releasePermit(rt); - return rt; - } - - private void releasePermit(WriteMessage rt) { - if (rt != null) { - if (rt.getMessage() instanceof Command) { - Command cmd = (Command) rt.getMessage(); - if (cmd.isNoreply()) { - this.flowControl.release(); - } - } - - } - } - - @Override - public int drainTo(Collection c) { - return super.drainTo(c); - } - - @Override - public int drainTo(Collection c, int maxElements) { - return super.drainTo(c, maxElements); - } - - @Override - public Iterator iterator() { - return super.iterator(); - } - - @Override - public WriteMessage peek() { - return super.peek(); - } - - @Override - public boolean isEmpty() { - return super.isEmpty(); - } - - @Override - public boolean hasWaitingConsumer() { - return super.hasWaitingConsumer(); - } - - @Override - public int size() { - return super.size(); - } - - @Override - public int getWaitingConsumerCount() { - return super.getWaitingConsumerCount(); - } - - @Override - public int remainingCapacity() { - return super.remainingCapacity(); - } - -} +package net.rubyeye.xmemcached.impl; + +import java.util.Collection; +import java.util.Iterator; +import java.util.concurrent.TimeUnit; +import net.rubyeye.xmemcached.FlowControl; +import net.rubyeye.xmemcached.command.Command; +import com.google.code.yanf4j.core.WriteMessage; +import com.google.code.yanf4j.util.LinkedTransferQueue; + +public class FlowControlLinkedTransferQueue extends LinkedTransferQueue { + private FlowControl flowControl; + + public FlowControlLinkedTransferQueue(FlowControl flowControl) { + super(); + this.flowControl = flowControl; + } + + private void checkPermits(WriteMessage e) { + if (e.getMessage() instanceof Command) { + Command cmd = (Command) e.getMessage(); + if (cmd.isNoreply()) { + int i = 3; + boolean success = false; + while (i-- > 0) { + if (this.flowControl.aquire()) { + success = true; + break; + } else { + // reduce consuming cpu + Thread.yield(); + } + } + if (!success) + throw new IllegalStateException( + "No permit for noreply operation,max=" + flowControl.max()); + } + } + } + + @Override + public void put(WriteMessage e) throws InterruptedException { + checkPermits(e); + super.put(e); + } + + @Override + public boolean offer(WriteMessage e, long timeout, TimeUnit unit) throws InterruptedException { + checkPermits(e); + return super.offer(e, timeout, unit); + } + + @Override + public boolean offer(WriteMessage e) { + checkPermits(e); + return super.offer(e); + } + + @Override + public void transfer(WriteMessage e) throws InterruptedException { + checkPermits(e); + super.transfer(e); + } + + @Override + public boolean tryTransfer(WriteMessage e, long timeout, TimeUnit unit) + throws InterruptedException { + checkPermits(e); + return super.tryTransfer(e, timeout, unit); + } + + @Override + public boolean tryTransfer(WriteMessage e) { + checkPermits(e); + return super.tryTransfer(e); + } + + @Override + public WriteMessage take() throws InterruptedException { + WriteMessage rt = super.take(); + releasePermit(rt); + return rt; + } + + @Override + public WriteMessage poll(long timeout, TimeUnit unit) throws InterruptedException { + WriteMessage rt = super.poll(timeout, unit); + releasePermit(rt); + return rt; + } + + @Override + public WriteMessage poll() { + WriteMessage rt = super.poll(); + releasePermit(rt); + return rt; + } + + private void releasePermit(WriteMessage rt) { + if (rt != null) { + if (rt.getMessage() instanceof Command) { + Command cmd = (Command) rt.getMessage(); + if (cmd.isNoreply()) { + this.flowControl.release(); + } + } + + } + } + + @Override + public int drainTo(Collection c) { + return super.drainTo(c); + } + + @Override + public int drainTo(Collection c, int maxElements) { + return super.drainTo(c, maxElements); + } + + @Override + public Iterator iterator() { + return super.iterator(); + } + + @Override + public WriteMessage peek() { + return super.peek(); + } + + @Override + public boolean isEmpty() { + return super.isEmpty(); + } + + @Override + public boolean hasWaitingConsumer() { + return super.hasWaitingConsumer(); + } + + @Override + public int size() { + return super.size(); + } + + @Override + public int getWaitingConsumerCount() { + return super.getWaitingConsumerCount(); + } + + @Override + public int remainingCapacity() { + return super.remainingCapacity(); + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/impl/KetamaMemcachedSessionLocator.java b/src/main/java/net/rubyeye/xmemcached/impl/KetamaMemcachedSessionLocator.java index fba49e547..3f2c7419d 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/KetamaMemcachedSessionLocator.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/KetamaMemcachedSessionLocator.java @@ -1,270 +1,251 @@ -/** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 net.rubyeye.xmemcached.impl; - -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.SortedMap; -import java.util.TreeMap; - -import com.google.code.yanf4j.core.Session; - -import net.rubyeye.xmemcached.HashAlgorithm; -import net.rubyeye.xmemcached.networking.MemcachedSession; -import net.rubyeye.xmemcached.utils.InetSocketAddressWrapper; - -/** - * ConnectionFactory instance that sets up a ketama compatible connection. - * - *

- * This implementation piggy-backs on the functionality of the - * DefaultConnectionFactory in terms of connections and queue - * handling. Where it differs is that it uses both the - * KetamaNodeLocator - * and the HashAlgorithm.KETAMA_HASH to provide consistent node - * hashing. - * - * @see http://www.last.fm/user/RJ/journal/2007/04/10/392555/ - * - *

- */ -/** - * Consistent Hash Algorithm implementation,based on TreeMap.tailMap(hash) - * method. - * - * @author dennis - * - */ -public class KetamaMemcachedSessionLocator - extends - AbstractMemcachedSessionLocator { - - static final int NUM_REPS = 160; - private transient volatile TreeMap> ketamaSessions = new TreeMap>(); - private final HashAlgorithm hashAlg; - private int maxTries; - - /** - * compatible with nginx-upstream-consistent,patched by wolfg1969 - */ - static final int DEFAULT_PORT = 11211; - private final boolean cwNginxUpstreamConsistent; - private final boolean gwhalinMemcachedJavaClientCompatibiltyConsistent; - - /** - * Create a KetamaMemcachedSessionLocator with default config. - */ - public KetamaMemcachedSessionLocator() { - this.hashAlg = HashAlgorithm.KETAMA_HASH; - this.cwNginxUpstreamConsistent = false; - this.gwhalinMemcachedJavaClientCompatibiltyConsistent = false; - } - - /** - * Create a KetamaMemcachedSessionLocator - * - * @param cwNginxUpstreamConsistent - * true if compatible with nginx up stream memcached consistent - * algorithm. - */ - public KetamaMemcachedSessionLocator(boolean cwNginxUpstreamConsistent) { - this.hashAlg = HashAlgorithm.KETAMA_HASH; - this.cwNginxUpstreamConsistent = cwNginxUpstreamConsistent; - this.gwhalinMemcachedJavaClientCompatibiltyConsistent = false; - } - - /** - * Create a KetamaMemcachedSessionLocator with a special hash algorithm. - * - * @param alg - */ - public KetamaMemcachedSessionLocator(HashAlgorithm alg) { - this.hashAlg = alg; - this.cwNginxUpstreamConsistent = false; - this.gwhalinMemcachedJavaClientCompatibiltyConsistent = false; - } - - public KetamaMemcachedSessionLocator(HashAlgorithm alg, - boolean cwNginxUpstreamConsistent) { - this.hashAlg = alg; - this.cwNginxUpstreamConsistent = cwNginxUpstreamConsistent; - this.gwhalinMemcachedJavaClientCompatibiltyConsistent = false; - } - - public KetamaMemcachedSessionLocator(HashAlgorithm alg, - boolean cwNginxUpstreamConsistent, - boolean gwhalinMemcachedJavaClientCompatibiltyConsistent) { - this.hashAlg = HashAlgorithm.KETAMA_HASH; - this.cwNginxUpstreamConsistent = cwNginxUpstreamConsistent; - this.gwhalinMemcachedJavaClientCompatibiltyConsistent = gwhalinMemcachedJavaClientCompatibiltyConsistent; - } - - public KetamaMemcachedSessionLocator(List list, - HashAlgorithm alg) { - super(); - this.hashAlg = alg; - this.cwNginxUpstreamConsistent = false; - this.gwhalinMemcachedJavaClientCompatibiltyConsistent = false; - this.buildMap(list, alg); - } - - private final void buildMap(Collection list, HashAlgorithm alg) { - TreeMap> sessionMap = new TreeMap>(); - - for (Session session : list) { - String sockStr = this.getSockStr(session); - /** - * Duplicate 160 X weight references - */ - int numReps = NUM_REPS; - if (session instanceof MemcachedSession) { - numReps *= ((MemcachedSession) session).getWeight(); - } - if (alg == HashAlgorithm.KETAMA_HASH) { - for (int i = 0; i < numReps / 4; i++) { - byte[] digest = HashAlgorithm.computeMd5(sockStr + "-" + i); - for (int h = 0; h < 4; h++) { - long k = (long) (digest[3 + h * 4] & 0xFF) << 24 - | (long) (digest[2 + h * 4] & 0xFF) << 16 - | (long) (digest[1 + h * 4] & 0xFF) << 8 - | digest[h * 4] & 0xFF; - this.getSessionList(sessionMap, k).add(session); - } - - } - } else { - for (int i = 0; i < numReps; i++) { - long key = alg.hash(sockStr + "-" + i); - this.getSessionList(sessionMap, key).add(session); - } - } - } - // sort session list. - for (List sessions : sessionMap.values()) { - Collections.sort(sessions, new Comparator() { - - public int compare(Session o1, Session o2) { - String sockStr1 = KetamaMemcachedSessionLocator.this - .getSockStr(o1); - String sockStr2 = KetamaMemcachedSessionLocator.this - .getSockStr(o2); - return sockStr1.compareTo(sockStr2); - } - - }); - } - this.ketamaSessions = sessionMap; - this.maxTries = list.size(); - } - - private String getSockStr(Session session) { - String sockStr = null; - if (this.cwNginxUpstreamConsistent) { - InetSocketAddress serverAddress = session.getRemoteSocketAddress(); - sockStr = serverAddress.getAddress().getHostAddress(); - if (serverAddress.getPort() != DEFAULT_PORT) { - sockStr = sockStr + ":" + serverAddress.getPort(); - } - } else { - if (session instanceof MemcachedSession) { - MemcachedSession memcachedSession = (MemcachedSession) session; - InetSocketAddressWrapper inetSocketAddressWrapper = memcachedSession - .getInetSocketAddressWrapper(); - if (this.gwhalinMemcachedJavaClientCompatibiltyConsistent) { - sockStr = inetSocketAddressWrapper.getInetSocketAddress() - .getHostName() + ":" - + inetSocketAddressWrapper.getInetSocketAddress() - .getPort(); - - } else { - // Always use the first time resolved address. - sockStr = inetSocketAddressWrapper.getRemoteAddressStr(); - } - } - if (sockStr == null) { - sockStr = String.valueOf(session.getRemoteSocketAddress()); - } - } - return sockStr; - } - - private List getSessionList( - TreeMap> sessionMap, long k) { - List sessionList = sessionMap.get(k); - if (sessionList == null) { - sessionList = new ArrayList(); - sessionMap.put(k, sessionList); - } - return sessionList; - } - - public final Session getSessionByKey(final String key) { - if (this.ketamaSessions == null || this.ketamaSessions.size() == 0) { - return null; - } - long hash = this.hashAlg.hash(key); - Session rv = this.getSessionByHash(hash); - int tries = 0; - while (!this.failureMode && (rv == null || rv.isClosed()) - && tries++ < this.maxTries) { - hash = this.nextHash(hash, key, tries); - rv = this.getSessionByHash(hash); - } - return rv; - } - - public final Session getSessionByHash(final long hash) { - TreeMap> sessionMap = this.ketamaSessions; - if (sessionMap.size() == 0) { - return null; - } - Long resultHash = hash; - if (!sessionMap.containsKey(hash)) { - // Java 1.6 adds a ceilingKey method, but xmemcached is compatible - // with jdk5,So use tailMap method to do this. - SortedMap> tailMap = sessionMap.tailMap(hash); - if (tailMap.isEmpty()) { - resultHash = sessionMap.firstKey(); - } else { - resultHash = tailMap.firstKey(); - } - } - // - // if (!sessionMap.containsKey(resultHash)) { - // resultHash = sessionMap.ceilingKey(resultHash); - // if (resultHash == null && sessionMap.size() > 0) { - // resultHash = sessionMap.firstKey(); - // } - // } - List sessionList = sessionMap.get(resultHash); - if (sessionList == null || sessionList.size() == 0) { - return null; - } - int size = sessionList.size(); - return sessionList.get((int) (resultHash % size)); - } - - public final long nextHash(long hashVal, String key, int tries) { - long tmpKey = this.hashAlg.hash(tries + key); - hashVal += (int) (tmpKey ^ tmpKey >>> 32); - hashVal &= 0xffffffffL; /* truncate to 32-bits */ - return hashVal; - } - - public final void updateSessions(final Collection list) { - this.buildMap(list, this.hashAlg); - } -} +/** + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.impl; + +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.SortedMap; +import java.util.TreeMap; +import com.google.code.yanf4j.core.Session; +import net.rubyeye.xmemcached.HashAlgorithm; +import net.rubyeye.xmemcached.networking.MemcachedSession; +import net.rubyeye.xmemcached.utils.InetSocketAddressWrapper; + +/** + * ConnectionFactory instance that sets up a ketama compatible connection. + * + *

+ * This implementation piggy-backs on the functionality of the DefaultConnectionFactory + * in terms of connections and queue handling. Where it differs is that it uses both the + * KetamaNodeLocator and the HashAlgorithm.KETAMA_HASH to provide consistent + * node hashing. + * + * @see http://www.last.fm/user/RJ/journal/2007/04/10/392555/ + * + *

+ */ +/** + * Consistent Hash Algorithm implementation,based on TreeMap.tailMap(hash) method. + * + * @author dennis + * + */ +public class KetamaMemcachedSessionLocator extends AbstractMemcachedSessionLocator { + + static final int NUM_REPS = 160; + private transient volatile TreeMap> ketamaSessions = + new TreeMap>(); + private final HashAlgorithm hashAlg; + private int maxTries; + + /** + * compatible with nginx-upstream-consistent,patched by wolfg1969 + */ + static final int DEFAULT_PORT = 11211; + private final boolean cwNginxUpstreamConsistent; + private final boolean gwhalinMemcachedJavaClientCompatibiltyConsistent; + + /** + * Create a KetamaMemcachedSessionLocator with default config. + */ + public KetamaMemcachedSessionLocator() { + this.hashAlg = HashAlgorithm.KETAMA_HASH; + this.cwNginxUpstreamConsistent = false; + this.gwhalinMemcachedJavaClientCompatibiltyConsistent = false; + } + + /** + * Create a KetamaMemcachedSessionLocator + * + * @param cwNginxUpstreamConsistent true if compatible with nginx up stream memcached consistent + * algorithm. + */ + public KetamaMemcachedSessionLocator(boolean cwNginxUpstreamConsistent) { + this.hashAlg = HashAlgorithm.KETAMA_HASH; + this.cwNginxUpstreamConsistent = cwNginxUpstreamConsistent; + this.gwhalinMemcachedJavaClientCompatibiltyConsistent = false; + } + + /** + * Create a KetamaMemcachedSessionLocator with a special hash algorithm. + * + * @param alg + */ + public KetamaMemcachedSessionLocator(HashAlgorithm alg) { + this.hashAlg = alg; + this.cwNginxUpstreamConsistent = false; + this.gwhalinMemcachedJavaClientCompatibiltyConsistent = false; + } + + public KetamaMemcachedSessionLocator(HashAlgorithm alg, boolean cwNginxUpstreamConsistent) { + this.hashAlg = alg; + this.cwNginxUpstreamConsistent = cwNginxUpstreamConsistent; + this.gwhalinMemcachedJavaClientCompatibiltyConsistent = false; + } + + public KetamaMemcachedSessionLocator(HashAlgorithm alg, boolean cwNginxUpstreamConsistent, + boolean gwhalinMemcachedJavaClientCompatibiltyConsistent) { + this.hashAlg = HashAlgorithm.KETAMA_HASH; + this.cwNginxUpstreamConsistent = cwNginxUpstreamConsistent; + this.gwhalinMemcachedJavaClientCompatibiltyConsistent = + gwhalinMemcachedJavaClientCompatibiltyConsistent; + } + + public KetamaMemcachedSessionLocator(List list, HashAlgorithm alg) { + super(); + this.hashAlg = alg; + this.cwNginxUpstreamConsistent = false; + this.gwhalinMemcachedJavaClientCompatibiltyConsistent = false; + this.buildMap(list, alg); + } + + private final void buildMap(Collection list, HashAlgorithm alg) { + TreeMap> sessionMap = new TreeMap>(); + + for (Session session : list) { + String sockStr = this.getSockStr(session); + /** + * Duplicate 160 X weight references + */ + int numReps = NUM_REPS; + if (session instanceof MemcachedSession) { + numReps *= ((MemcachedSession) session).getWeight(); + } + if (alg == HashAlgorithm.KETAMA_HASH) { + for (int i = 0; i < numReps / 4; i++) { + byte[] digest = HashAlgorithm.computeMd5(sockStr + "-" + i); + for (int h = 0; h < 4; h++) { + long k = + (long) (digest[3 + h * 4] & 0xFF) << 24 | (long) (digest[2 + h * 4] & 0xFF) << 16 + | (long) (digest[1 + h * 4] & 0xFF) << 8 | digest[h * 4] & 0xFF; + this.getSessionList(sessionMap, k).add(session); + } + + } + } else { + for (int i = 0; i < numReps; i++) { + long key = alg.hash(sockStr + "-" + i); + this.getSessionList(sessionMap, key).add(session); + } + } + } + // sort session list. + for (List sessions : sessionMap.values()) { + Collections.sort(sessions, new Comparator() { + + public int compare(Session o1, Session o2) { + String sockStr1 = KetamaMemcachedSessionLocator.this.getSockStr(o1); + String sockStr2 = KetamaMemcachedSessionLocator.this.getSockStr(o2); + return sockStr1.compareTo(sockStr2); + } + + }); + } + this.ketamaSessions = sessionMap; + this.maxTries = list.size(); + } + + private String getSockStr(Session session) { + String sockStr = null; + if (this.cwNginxUpstreamConsistent) { + InetSocketAddress serverAddress = session.getRemoteSocketAddress(); + sockStr = serverAddress.getAddress().getHostAddress(); + if (serverAddress.getPort() != DEFAULT_PORT) { + sockStr = sockStr + ":" + serverAddress.getPort(); + } + } else { + if (session instanceof MemcachedSession) { + MemcachedSession memcachedSession = (MemcachedSession) session; + InetSocketAddressWrapper inetSocketAddressWrapper = + memcachedSession.getInetSocketAddressWrapper(); + if (this.gwhalinMemcachedJavaClientCompatibiltyConsistent) { + sockStr = inetSocketAddressWrapper.getInetSocketAddress().getHostName() + ":" + + inetSocketAddressWrapper.getInetSocketAddress().getPort(); + + } else { + // Always use the first time resolved address. + sockStr = inetSocketAddressWrapper.getRemoteAddressStr(); + } + } + if (sockStr == null) { + sockStr = String.valueOf(session.getRemoteSocketAddress()); + } + } + return sockStr; + } + + private List getSessionList(TreeMap> sessionMap, long k) { + List sessionList = sessionMap.get(k); + if (sessionList == null) { + sessionList = new ArrayList(); + sessionMap.put(k, sessionList); + } + return sessionList; + } + + public final Session getSessionByKey(final String key) { + if (this.ketamaSessions == null || this.ketamaSessions.size() == 0) { + return null; + } + long hash = this.hashAlg.hash(key); + Session rv = this.getSessionByHash(hash); + int tries = 0; + while (!this.failureMode && (rv == null || rv.isClosed()) && tries++ < this.maxTries) { + hash = this.nextHash(hash, key, tries); + rv = this.getSessionByHash(hash); + } + return rv; + } + + public final Session getSessionByHash(final long hash) { + TreeMap> sessionMap = this.ketamaSessions; + if (sessionMap.size() == 0) { + return null; + } + Long resultHash = hash; + if (!sessionMap.containsKey(hash)) { + // Java 1.6 adds a ceilingKey method, but xmemcached is compatible + // with jdk5,So use tailMap method to do this. + SortedMap> tailMap = sessionMap.tailMap(hash); + if (tailMap.isEmpty()) { + resultHash = sessionMap.firstKey(); + } else { + resultHash = tailMap.firstKey(); + } + } + // + // if (!sessionMap.containsKey(resultHash)) { + // resultHash = sessionMap.ceilingKey(resultHash); + // if (resultHash == null && sessionMap.size() > 0) { + // resultHash = sessionMap.firstKey(); + // } + // } + List sessionList = sessionMap.get(resultHash); + if (sessionList == null || sessionList.size() == 0) { + return null; + } + int size = sessionList.size(); + return sessionList.get((int) (resultHash % size)); + } + + public final long nextHash(long hashVal, String key, int tries) { + long tmpKey = this.hashAlg.hash(tries + key); + hashVal += (int) (tmpKey ^ tmpKey >>> 32); + hashVal &= 0xffffffffL; /* truncate to 32-bits */ + return hashVal; + } + + public final void updateSessions(final Collection list) { + this.buildMap(list, this.hashAlg); + } +} diff --git a/src/main/java/net/rubyeye/xmemcached/impl/KeyIteratorImpl.java b/src/main/java/net/rubyeye/xmemcached/impl/KeyIteratorImpl.java index 81e894280..8ca39e53b 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/KeyIteratorImpl.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/KeyIteratorImpl.java @@ -7,14 +7,12 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; - import net.rubyeye.xmemcached.KeyIterator; import net.rubyeye.xmemcached.MemcachedClient; import net.rubyeye.xmemcached.command.text.TextCacheDumpCommand; import net.rubyeye.xmemcached.exception.MemcachedException; import net.rubyeye.xmemcached.exception.MemcachedServerException; import net.rubyeye.xmemcached.utils.Protocol; - import com.google.code.yanf4j.core.Session; /** @@ -24,86 +22,76 @@ * */ public final class KeyIteratorImpl implements KeyIterator { - private final LinkedList itemNumbersList; - private LinkedList currentKeyList; - private final MemcachedClient memcachedClient; - private final InetSocketAddress inetSocketAddress; - private long opTimeout = 1000; + private final LinkedList itemNumbersList; + private LinkedList currentKeyList; + private final MemcachedClient memcachedClient; + private final InetSocketAddress inetSocketAddress; + private long opTimeout = 1000; - public KeyIteratorImpl(LinkedList itemNumbersList, - MemcachedClient memcachedClient, - InetSocketAddress inetSocketAddress) { - super(); - this.itemNumbersList = itemNumbersList; - this.memcachedClient = memcachedClient; - this.inetSocketAddress = inetSocketAddress; - } + public KeyIteratorImpl(LinkedList itemNumbersList, MemcachedClient memcachedClient, + InetSocketAddress inetSocketAddress) { + super(); + this.itemNumbersList = itemNumbersList; + this.memcachedClient = memcachedClient; + this.inetSocketAddress = inetSocketAddress; + } - public final InetSocketAddress getServerAddress() { - return this.inetSocketAddress; - } + public final InetSocketAddress getServerAddress() { + return this.inetSocketAddress; + } - public final void setOpTimeout(long opTimeout) { - this.opTimeout = opTimeout; - } + public final void setOpTimeout(long opTimeout) { + this.opTimeout = opTimeout; + } - public void close() { - this.itemNumbersList.clear(); - this.currentKeyList.clear(); - this.currentKeyList = null; - } + public void close() { + this.itemNumbersList.clear(); + this.currentKeyList.clear(); + this.currentKeyList = null; + } - public boolean hasNext() { - return (this.itemNumbersList != null && !this.itemNumbersList.isEmpty()) - || (this.currentKeyList != null - && !this.currentKeyList.isEmpty()); - } + public boolean hasNext() { + return (this.itemNumbersList != null && !this.itemNumbersList.isEmpty()) + || (this.currentKeyList != null && !this.currentKeyList.isEmpty()); + } - @SuppressWarnings("unchecked") - public String next() - throws MemcachedException, TimeoutException, InterruptedException { - if (!hasNext()) { - throw new NoSuchElementException(); - } + @SuppressWarnings("unchecked") + public String next() throws MemcachedException, TimeoutException, InterruptedException { + if (!hasNext()) { + throw new NoSuchElementException(); + } - if (this.currentKeyList != null && !this.currentKeyList.isEmpty()) { - return this.currentKeyList.remove(); - } + if (this.currentKeyList != null && !this.currentKeyList.isEmpty()) { + return this.currentKeyList.remove(); + } - int itemNumber = this.itemNumbersList.remove(); - Queue sessions = this.memcachedClient.getConnector() - .getSessionByAddress(this.inetSocketAddress); - if (sessions == null || sessions.size() == 0) { - throw new MemcachedException( - "The memcached server is not connected,address=" - + this.inetSocketAddress); - } - Session session = sessions.peek(); - CountDownLatch latch = new CountDownLatch(1); - if (this.memcachedClient.getProtocol() == Protocol.Text) { - TextCacheDumpCommand textCacheDumpCommand = new TextCacheDumpCommand( - latch, itemNumber); - session.write(textCacheDumpCommand); - if (!latch.await(this.opTimeout, TimeUnit.MILLISECONDS)) { - throw new TimeoutException("stats cachedump timeout"); - } - if (textCacheDumpCommand.getException() != null) { - if (textCacheDumpCommand - .getException() instanceof MemcachedException) { - throw (MemcachedException) textCacheDumpCommand - .getException(); - } else { - throw new MemcachedServerException( - textCacheDumpCommand.getException()); - } - } - this.currentKeyList = (LinkedList) textCacheDumpCommand - .getResult(); - } else { - throw new MemcachedException(this.memcachedClient.getProtocol() - .name() - + " protocol doesn't support iterating all keys in memcached"); - } - return next(); - } + int itemNumber = this.itemNumbersList.remove(); + Queue sessions = + this.memcachedClient.getConnector().getSessionByAddress(this.inetSocketAddress); + if (sessions == null || sessions.size() == 0) { + throw new MemcachedException( + "The memcached server is not connected,address=" + this.inetSocketAddress); + } + Session session = sessions.peek(); + CountDownLatch latch = new CountDownLatch(1); + if (this.memcachedClient.getProtocol() == Protocol.Text) { + TextCacheDumpCommand textCacheDumpCommand = new TextCacheDumpCommand(latch, itemNumber); + session.write(textCacheDumpCommand); + if (!latch.await(this.opTimeout, TimeUnit.MILLISECONDS)) { + throw new TimeoutException("stats cachedump timeout"); + } + if (textCacheDumpCommand.getException() != null) { + if (textCacheDumpCommand.getException() instanceof MemcachedException) { + throw (MemcachedException) textCacheDumpCommand.getException(); + } else { + throw new MemcachedServerException(textCacheDumpCommand.getException()); + } + } + this.currentKeyList = (LinkedList) textCacheDumpCommand.getResult(); + } else { + throw new MemcachedException(this.memcachedClient.getProtocol().name() + + " protocol doesn't support iterating all keys in memcached"); + } + return next(); + } } diff --git a/src/main/java/net/rubyeye/xmemcached/impl/LibmemcachedMemcachedSessionLocator.java b/src/main/java/net/rubyeye/xmemcached/impl/LibmemcachedMemcachedSessionLocator.java index c77c9c155..3ec9d39a1 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/LibmemcachedMemcachedSessionLocator.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/LibmemcachedMemcachedSessionLocator.java @@ -1,13 +1,10 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.impl; @@ -17,124 +14,116 @@ import java.util.Random; import java.util.SortedMap; import java.util.TreeMap; - import net.rubyeye.xmemcached.HashAlgorithm; import net.rubyeye.xmemcached.impl.AbstractMemcachedSessionLocator; - import com.google.code.yanf4j.core.Session; /** - * Consistent Hash Algorithm implementation is compatible with libmemcached - * method. + * Consistent Hash Algorithm implementation is compatible with libmemcached method. * * @author dennis * */ -public class LibmemcachedMemcachedSessionLocator - extends - AbstractMemcachedSessionLocator { +public class LibmemcachedMemcachedSessionLocator extends AbstractMemcachedSessionLocator { - static final int DEFAULT_NUM_REPS = 100; - private transient volatile TreeMap> ketamaSessions = new TreeMap>(); - private int maxTries; - private int numReps = DEFAULT_NUM_REPS; - private final Random random = new Random(); - private HashAlgorithm hashAlgorithm = HashAlgorithm.ONE_AT_A_TIME; + static final int DEFAULT_NUM_REPS = 100; + private transient volatile TreeMap> ketamaSessions = + new TreeMap>(); + private int maxTries; + private int numReps = DEFAULT_NUM_REPS; + private final Random random = new Random(); + private HashAlgorithm hashAlgorithm = HashAlgorithm.ONE_AT_A_TIME; - public LibmemcachedMemcachedSessionLocator() { - } + public LibmemcachedMemcachedSessionLocator() {} - public LibmemcachedMemcachedSessionLocator(int numReps, - HashAlgorithm hashAlgorithm) { - super(); - this.numReps = numReps; - this.hashAlgorithm = hashAlgorithm; - } + public LibmemcachedMemcachedSessionLocator(int numReps, HashAlgorithm hashAlgorithm) { + super(); + this.numReps = numReps; + this.hashAlgorithm = hashAlgorithm; + } - private final void buildMap(Collection list, HashAlgorithm alg) { - TreeMap> sessionMap = new TreeMap>(); + private final void buildMap(Collection list, HashAlgorithm alg) { + TreeMap> sessionMap = new TreeMap>(); - for (Session session : list) { - String sockStr = null; - if (session.getRemoteSocketAddress().getPort() != 11211) { - sockStr = session.getRemoteSocketAddress().getHostName() + ":" - + session.getRemoteSocketAddress().getPort(); - } else { - sockStr = session.getRemoteSocketAddress().getHostName(); - } - for (int i = 0; i < this.numReps; i++) { - long key = hashAlgorithm.hash(sockStr + "-" + i); - this.getSessionList(sessionMap, key).add(session); - } - } - this.ketamaSessions = sessionMap; - this.maxTries = list.size(); - } + for (Session session : list) { + String sockStr = null; + if (session.getRemoteSocketAddress().getPort() != 11211) { + sockStr = session.getRemoteSocketAddress().getHostName() + ":" + + session.getRemoteSocketAddress().getPort(); + } else { + sockStr = session.getRemoteSocketAddress().getHostName(); + } + for (int i = 0; i < this.numReps; i++) { + long key = hashAlgorithm.hash(sockStr + "-" + i); + this.getSessionList(sessionMap, key).add(session); + } + } + this.ketamaSessions = sessionMap; + this.maxTries = list.size(); + } - private List getSessionList( - TreeMap> sessionMap, long k) { - List sessionList = sessionMap.get(k); - if (sessionList == null) { - sessionList = new ArrayList(); - sessionMap.put(k, sessionList); - } - return sessionList; - } + private List getSessionList(TreeMap> sessionMap, long k) { + List sessionList = sessionMap.get(k); + if (sessionList == null) { + sessionList = new ArrayList(); + sessionMap.put(k, sessionList); + } + return sessionList; + } - public final Session getSessionByKey(final String key) { - if (this.ketamaSessions == null || this.ketamaSessions.size() == 0) { - return null; - } - long hash = hashAlgorithm.hash(key); - Session rv = this.getSessionByHash(hash); - int tries = 0; - while (!this.failureMode && (rv == null || rv.isClosed()) - && tries++ < this.maxTries) { - hash = this.nextHash(hash, key, tries); - rv = this.getSessionByHash(hash); - } - return rv; - } + public final Session getSessionByKey(final String key) { + if (this.ketamaSessions == null || this.ketamaSessions.size() == 0) { + return null; + } + long hash = hashAlgorithm.hash(key); + Session rv = this.getSessionByHash(hash); + int tries = 0; + while (!this.failureMode && (rv == null || rv.isClosed()) && tries++ < this.maxTries) { + hash = this.nextHash(hash, key, tries); + rv = this.getSessionByHash(hash); + } + return rv; + } - public final Session getSessionByHash(final long hash) { - TreeMap> sessionMap = this.ketamaSessions; - if (sessionMap.size() == 0) { - return null; - } - Long resultHash = hash; - if (!sessionMap.containsKey(hash)) { - // Java 1.6 adds a ceilingKey method, but xmemcached is compatible - // with jdk5,So use tailMap method to do this. - SortedMap> tailMap = sessionMap.tailMap(hash); - if (tailMap.isEmpty()) { - resultHash = sessionMap.firstKey(); - } else { - resultHash = tailMap.firstKey(); - } - } - // - // if (!sessionMap.containsKey(resultHash)) { - // resultHash = sessionMap.ceilingKey(resultHash); - // if (resultHash == null && sessionMap.size() > 0) { - // resultHash = sessionMap.firstKey(); - // } - // } - List sessionList = sessionMap.get(resultHash); - if (sessionList == null || sessionList.size() == 0) { - return null; - } - int size = sessionList.size(); - return sessionList.get(this.random.nextInt(size)); - } + public final Session getSessionByHash(final long hash) { + TreeMap> sessionMap = this.ketamaSessions; + if (sessionMap.size() == 0) { + return null; + } + Long resultHash = hash; + if (!sessionMap.containsKey(hash)) { + // Java 1.6 adds a ceilingKey method, but xmemcached is compatible + // with jdk5,So use tailMap method to do this. + SortedMap> tailMap = sessionMap.tailMap(hash); + if (tailMap.isEmpty()) { + resultHash = sessionMap.firstKey(); + } else { + resultHash = tailMap.firstKey(); + } + } + // + // if (!sessionMap.containsKey(resultHash)) { + // resultHash = sessionMap.ceilingKey(resultHash); + // if (resultHash == null && sessionMap.size() > 0) { + // resultHash = sessionMap.firstKey(); + // } + // } + List sessionList = sessionMap.get(resultHash); + if (sessionList == null || sessionList.size() == 0) { + return null; + } + int size = sessionList.size(); + return sessionList.get(this.random.nextInt(size)); + } - public final long nextHash(long hashVal, String key, int tries) { - long tmpKey = hashAlgorithm.hash(tries + key); - hashVal += (int) (tmpKey ^ tmpKey >>> 32); - hashVal &= 0xffffffffL; /* truncate to 32-bits */ - return hashVal; - } + public final long nextHash(long hashVal, String key, int tries) { + long tmpKey = hashAlgorithm.hash(tries + key); + hashVal += (int) (tmpKey ^ tmpKey >>> 32); + hashVal &= 0xffffffffL; /* truncate to 32-bits */ + return hashVal; + } - public final void updateSessions(final Collection list) { - this.buildMap(list, null); - } + public final void updateSessions(final Collection list) { + this.buildMap(list, null); + } } diff --git a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedClientStateListenerAdapter.java b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedClientStateListenerAdapter.java index bc7bb264b..0b9dfb121 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedClientStateListenerAdapter.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedClientStateListenerAdapter.java @@ -1,30 +1,23 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.impl; import net.rubyeye.xmemcached.MemcachedClient; import net.rubyeye.xmemcached.MemcachedClientStateListener; - import com.google.code.yanf4j.core.Controller; import com.google.code.yanf4j.core.ControllerStateListener; @@ -34,49 +27,46 @@ * @author dennis * */ -public class MemcachedClientStateListenerAdapter - implements - ControllerStateListener { - private final MemcachedClientStateListener memcachedClientStateListener; - private final MemcachedClient memcachedClient; +public class MemcachedClientStateListenerAdapter implements ControllerStateListener { + private final MemcachedClientStateListener memcachedClientStateListener; + private final MemcachedClient memcachedClient; - public MemcachedClientStateListenerAdapter( - MemcachedClientStateListener memcachedClientStateListener, - MemcachedClient memcachedClient) { - super(); - this.memcachedClientStateListener = memcachedClientStateListener; - this.memcachedClient = memcachedClient; - } + public MemcachedClientStateListenerAdapter( + MemcachedClientStateListener memcachedClientStateListener, MemcachedClient memcachedClient) { + super(); + this.memcachedClientStateListener = memcachedClientStateListener; + this.memcachedClient = memcachedClient; + } - public final MemcachedClientStateListener getMemcachedClientStateListener() { - return this.memcachedClientStateListener; - } + public final MemcachedClientStateListener getMemcachedClientStateListener() { + return this.memcachedClientStateListener; + } - public final MemcachedClient getMemcachedClient() { - return this.memcachedClient; - } + public final MemcachedClient getMemcachedClient() { + return this.memcachedClient; + } - public final void onAllSessionClosed(Controller acceptor) { + public final void onAllSessionClosed(Controller acceptor) { - } + } - public final void onException(Controller acceptor, Throwable t) { - this.memcachedClientStateListener.onException(this.memcachedClient, t); + public final void onException(Controller acceptor, Throwable t) { + this.memcachedClientStateListener.onException(this.memcachedClient, t); - } + } - public final void onReady(Controller acceptor) { + public final void onReady(Controller acceptor) { - } + } - public final void onStarted(Controller acceptor) { - this.memcachedClientStateListener.onStarted(this.memcachedClient); + public final void onStarted(Controller acceptor) { + this.memcachedClientStateListener.onStarted(this.memcachedClient); - } + } - public final void onStopped(Controller acceptor) { - this.memcachedClientStateListener.onShutDown(this.memcachedClient); + public final void onStopped(Controller acceptor) { + this.memcachedClientStateListener.onShutDown(this.memcachedClient); - } + } } diff --git a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java index 90e49d42a..5010a2690 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedConnector.java @@ -1,721 +1,660 @@ -/** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 net.rubyeye.xmemcached.impl; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.nio.channels.SelectionKey; -import java.nio.channels.Selector; -import java.nio.channels.SocketChannel; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Queue; -import java.util.Random; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.DelayQueue; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import net.rubyeye.xmemcached.CommandFactory; -import net.rubyeye.xmemcached.FlowControl; -import net.rubyeye.xmemcached.MemcachedClient; -import net.rubyeye.xmemcached.MemcachedOptimizer; -import net.rubyeye.xmemcached.MemcachedSessionLocator; -import net.rubyeye.xmemcached.buffer.BufferAllocator; -import net.rubyeye.xmemcached.command.Command; -import net.rubyeye.xmemcached.exception.MemcachedException; -import net.rubyeye.xmemcached.networking.Connector; -import net.rubyeye.xmemcached.networking.MemcachedSession; -import net.rubyeye.xmemcached.utils.InetSocketAddressWrapper; -import net.rubyeye.xmemcached.utils.Protocol; - -import com.google.code.yanf4j.config.Configuration; -import com.google.code.yanf4j.core.Controller; -import com.google.code.yanf4j.core.ControllerStateListener; -import com.google.code.yanf4j.core.EventType; -import com.google.code.yanf4j.core.Session; -import com.google.code.yanf4j.core.WriteMessage; -import com.google.code.yanf4j.nio.NioSession; -import com.google.code.yanf4j.nio.NioSessionConfig; -import com.google.code.yanf4j.nio.impl.SocketChannelController; -import com.google.code.yanf4j.util.ConcurrentHashSet; -import com.google.code.yanf4j.util.SystemUtils; - -/** - * Connected session manager - * - * @author dennis - */ -public class MemcachedConnector extends SocketChannelController - implements - Connector { - private final DelayQueue waitingQueue = new DelayQueue(); - private BufferAllocator bufferAllocator; - - private final Set removedAddrSet = new ConcurrentHashSet(); - - private final MemcachedOptimizer optimiezer; - private long healSessionInterval = MemcachedClient.DEFAULT_HEAL_SESSION_INTERVAL; - private int connectionPoolSize; // session pool size - protected Protocol protocol; - private boolean enableHealSession = true; - private final CommandFactory commandFactory; - private boolean failureMode; - - private final ConcurrentHashMap/* - * standby - * sessions - */> standbySessionMap = new ConcurrentHashMap>(); - - private final FlowControl flowControl; - - private volatile boolean shuttingDown = false; - - public void shuttingDown() { - this.shuttingDown = true; - } - - public void setSessionLocator(MemcachedSessionLocator sessionLocator) { - this.sessionLocator = sessionLocator; - } - - /** - * Session monitor for healing sessions. - * - * @author dennis - * - */ - class SessionMonitor extends Thread { - public SessionMonitor() { - this.setName("Heal-Session-Thread"); - } - - @Override - public void run() { - while (MemcachedConnector.this.isStarted() - && MemcachedConnector.this.enableHealSession) { - ReconnectRequest request = null; - try { - request = MemcachedConnector.this.waitingQueue.take(); - - InetSocketAddress address = request - .getInetSocketAddressWrapper() - .getInetSocketAddress(); - - if (!MemcachedConnector.this.removedAddrSet - .contains(address)) { - boolean connected = false; - Future future = MemcachedConnector.this - .connect(request.getInetSocketAddressWrapper()); - request.setTries(request.getTries() + 1); - try { - log.info("Trying to connect to " - + address.getAddress().getHostAddress() - + ":" + address.getPort() + " for " - + request.getTries() + " times"); - if (!future.get( - MemcachedClient.DEFAULT_CONNECT_TIMEOUT, - TimeUnit.MILLISECONDS)) { - connected = false; - } else { - connected = true; - } - } catch (TimeoutException e) { - future.cancel(true); - } catch (ExecutionException e) { - future.cancel(true); - } finally { - if (!connected) { - this.rescheduleConnectRequest(request); - } else { - continue; - } - } - } else { - log.info( - "Remove invalid reconnect task for " + address); - // remove reconnect task - } - } catch (InterruptedException e) { - // ignore,check status - } catch (Exception e) { - log.error("SessionMonitor connect error", e); - this.rescheduleConnectRequest(request); - } - } - } - - private void rescheduleConnectRequest(ReconnectRequest request) { - if (request == null) { - return; - } - InetSocketAddress address = request.getInetSocketAddressWrapper() - .getInetSocketAddress(); - // update timestamp for next reconnecting - request.updateNextReconnectTimeStamp( - MemcachedConnector.this.healSessionInterval - * request.getTries()); - log.error("Reconnected to " + address + " fail"); - // add to tail - MemcachedConnector.this.waitingQueue.offer(request); - } - } - - public void setEnableHealSession(boolean enableHealSession) { - this.enableHealSession = enableHealSession; - // wake up session monitor thread. - if (this.sessionMonitor != null && this.sessionMonitor.isAlive()) { - this.sessionMonitor.interrupt(); - } - } - - public Queue getReconnectRequestQueue() { - return this.waitingQueue; - } - - @Override - public Set getSessionSet() { - Collection> sessionQueues = this.sessionMap.values(); - Set result = new HashSet(); - for (Queue queue : sessionQueues) { - result.addAll(queue); - } - return result; - } - - public final void setHealSessionInterval(long healConnectionInterval) { - this.healSessionInterval = healConnectionInterval; - } - - public long getHealSessionInterval() { - return this.healSessionInterval; - } - - public void setOptimizeGet(boolean optimiezeGet) { - ((OptimizerMBean) this.optimiezer).setOptimizeGet(optimiezeGet); - } - - public void setOptimizeMergeBuffer(boolean optimizeMergeBuffer) { - ((OptimizerMBean) this.optimiezer) - .setOptimizeMergeBuffer(optimizeMergeBuffer); - } - - public Protocol getProtocol() { - return this.protocol; - } - - protected MemcachedSessionLocator sessionLocator; - - protected final ConcurrentHashMap> sessionMap = new ConcurrentHashMap>(); - - public synchronized void addSession(Session session) { - MemcachedSession tcpSession = (MemcachedSession) session; - - InetSocketAddressWrapper addrWrapper = tcpSession - .getInetSocketAddressWrapper(); - // Remember the first time address resolved and use it in all - // application lifecycle. - if (addrWrapper.getRemoteAddressStr() == null) { - addrWrapper.setRemoteAddressStr( - String.valueOf(session.getRemoteSocketAddress())); - } - - InetSocketAddress mainNodeAddress = addrWrapper.getMainNodeAddress(); - if (mainNodeAddress != null) { - // It is a standby session - this.addStandbySession(session, mainNodeAddress, - addrWrapper.getResolvedMainNodeSocketAddress(), - addrWrapper); - } else { - // It is a main session - this.addMainSession(session, addrWrapper.getResolvedSocketAddress(), - addrWrapper); - // Update main sessions - this.updateSessions(); - } - } - - private void addMainSession(Session session, - InetSocketAddress lastReolvedAddr, - InetSocketAddressWrapper addrWrapper) { - InetSocketAddress remoteSocketAddress = session - .getRemoteSocketAddress(); - log.info("Add a session: " - + SystemUtils.getRawAddress(remoteSocketAddress) + ":" - + remoteSocketAddress.getPort()); - if (lastReolvedAddr != null - && !lastReolvedAddr.equals(remoteSocketAddress)) { - log.warn("Memcached node {} is resolved into {}.", lastReolvedAddr, - remoteSocketAddress); - // Remove and closed old resolved address. - Queue sessions = sessionMap.remove(lastReolvedAddr); - if (sessions != null) { - for (Session s : sessions) { - ((MemcachedSession) s).setAllowReconnect(false); - s.close(); - } - } - // updated resolve addr - addrWrapper.setResolvedSocketAddress(remoteSocketAddress); - } - Queue sessions = this.sessionMap.get(remoteSocketAddress); - if (sessions == null) { - sessions = new ConcurrentLinkedQueue(); - Queue oldSessions = this.sessionMap - .putIfAbsent(remoteSocketAddress, sessions); - if (null != oldSessions) { - sessions = oldSessions; - } - } - // If it is in failure mode,remove closed session from list - if (this.failureMode) { - Iterator it = sessions.iterator(); - while (it.hasNext()) { - Session tmp = it.next(); - if (tmp.isClosed()) { - it.remove(); - break; - } - } - } - - sessions.offer(session); - // Remove old session and close it - while (sessions.size() > this.connectionPoolSize) { - Session oldSession = sessions.poll(); - ((MemcachedSession) oldSession).setAllowReconnect(false); - oldSession.close(); - } - } - - private void addStandbySession(Session session, - InetSocketAddress mainNodeAddress, - InetSocketAddress lastResolvedMainAddr, - InetSocketAddressWrapper addrWrapper) { - InetSocketAddress remoteSocketAddress = session - .getRemoteSocketAddress(); - log.info("Add a standby session: " - + SystemUtils.getRawAddress(remoteSocketAddress) + ":" - + remoteSocketAddress.getPort() + " for " - + SystemUtils.getRawAddress(mainNodeAddress) + ":" - + mainNodeAddress.getPort()); - if (lastResolvedMainAddr != null - && !lastResolvedMainAddr.equals(remoteSocketAddress)) { - log.warn("Memcached node {} is resolved into {}.", - lastResolvedMainAddr, remoteSocketAddress); - // Remove and closed old resolved address. - List sessions = standbySessionMap - .remove(lastResolvedMainAddr); - if (sessions != null) { - for (Session s : sessions) { - ((MemcachedSession) s).setAllowReconnect(false); - s.close(); - } - } - addrWrapper.setResolvedMainNodeSocketAddress(remoteSocketAddress); - } - List sessions = this.standbySessionMap.get(mainNodeAddress); - if (sessions == null) { - sessions = new CopyOnWriteArrayList(); - List oldSessions = this.standbySessionMap - .putIfAbsent(mainNodeAddress, sessions); - if (null != oldSessions) { - sessions = oldSessions; - } - } - sessions.add(session); - } - - public List getSessionListBySocketAddress( - InetSocketAddress inetSocketAddress) { - Queue queue = this.sessionMap.get(inetSocketAddress); - if (queue != null) { - return new ArrayList(queue); - } else { - return null; - } - } - - public void removeReconnectRequest(InetSocketAddress inetSocketAddress) { - this.removedAddrSet.add(inetSocketAddress); - Iterator it = this.waitingQueue.iterator(); - while (it.hasNext()) { - ReconnectRequest request = it.next(); - if (request.getInetSocketAddressWrapper().getInetSocketAddress() - .equals(inetSocketAddress)) { - it.remove(); - log.warn("Remove invalid reconnect task for " + request - .getInetSocketAddressWrapper().getInetSocketAddress()); - } - } - } - - private static final MemcachedSessionComparator sessionComparator = new MemcachedSessionComparator(); - - public final void updateSessions() { - Collection> sessionCollection = this.sessionMap.values(); - List sessionList = new ArrayList(20); - for (Queue sessions : sessionCollection) { - sessionList.addAll(sessions); - } - // sort the sessions to keep order - Collections.sort(sessionList, sessionComparator); - this.sessionLocator.updateSessions(sessionList); - } - - public synchronized void removeSession(Session session) { - MemcachedTCPSession tcpSession = (MemcachedTCPSession) session; - InetSocketAddressWrapper addrWrapper = tcpSession - .getInetSocketAddressWrapper(); - InetSocketAddress mainNodeAddr = addrWrapper.getMainNodeAddress(); - if (mainNodeAddr != null) { - this.removeStandbySession(session, mainNodeAddr); - } else { - this.removeMainSession(session); - } - } - - private void removeMainSession(Session session) { - InetSocketAddress remoteSocketAddress = session - .getRemoteSocketAddress(); - // If it was in failure mode,we don't remove closed session from list. - if (this.failureMode && ((MemcachedSession) session).isAllowReconnect() - && !this.shuttingDown && this.isStarted()) { - log.warn("Client in failure mode,we don't remove session " - + SystemUtils.getRawAddress(remoteSocketAddress) + ":" - + remoteSocketAddress.getPort()); - return; - } - log.info("Remove a session: " - + SystemUtils.getRawAddress(remoteSocketAddress) + ":" - + remoteSocketAddress.getPort()); - Queue sessionQueue = this.sessionMap - .get(session.getRemoteSocketAddress()); - if (null != sessionQueue) { - sessionQueue.remove(session); - if (sessionQueue.size() == 0) { - this.sessionMap.remove(session.getRemoteSocketAddress()); - } - this.updateSessions(); - } - } - - private void removeStandbySession(Session session, - InetSocketAddress mainNodeAddr) { - List sessionList = this.standbySessionMap.get(mainNodeAddr); - if (null != sessionList) { - sessionList.remove(session); - if (sessionList.size() == 0) { - this.standbySessionMap.remove(mainNodeAddr); - } - } - } - - @Override - protected void doStart() throws IOException { - this.setLocalSocketAddress(new InetSocketAddress("localhost", 0)); - } - - @Override - public void onConnect(SelectionKey key) throws IOException { - key.interestOps(key.interestOps() & ~SelectionKey.OP_CONNECT); - ConnectFuture future = (ConnectFuture) key.attachment(); - if (future == null || future.isCancelled()) { - this.cancelKey(key); - return; - } - try { - if (!((SocketChannel) key.channel()).finishConnect()) { - this.cancelKey(key); - future.failure(new IOException("Connect to " - + SystemUtils.getRawAddress( - future.getInetSocketAddressWrapper() - .getInetSocketAddress()) - + ":" + future.getInetSocketAddressWrapper() - .getInetSocketAddress().getPort() - + " fail")); - } else { - key.attach(null); - this.addSession( - this.createSession((SocketChannel) key.channel(), - future.getInetSocketAddressWrapper())); - future.setResult(Boolean.TRUE); - } - } catch (Exception e) { - future.failure(e); - this.cancelKey(key); - throw new IOException("Connect to " + SystemUtils.getRawAddress( - future.getInetSocketAddressWrapper().getInetSocketAddress()) - + ":" - + future.getInetSocketAddressWrapper() - .getInetSocketAddress().getPort() - + " fail," + e.getMessage()); - } - } - - private void cancelKey(SelectionKey key) throws IOException { - try { - if (key.channel() != null) { - key.channel().close(); - } - } finally { - key.cancel(); - } - } - - protected MemcachedTCPSession createSession(SocketChannel socketChannel, - InetSocketAddressWrapper wrapper) { - MemcachedTCPSession session = (MemcachedTCPSession) this - .buildSession(socketChannel); - session.setInetSocketAddressWrapper(wrapper); - this.selectorManager.registerSession(session, EventType.ENABLE_READ); - session.start(); - session.onEvent(EventType.CONNECTED, null); - return session; - } - - public void addToWatingQueue(ReconnectRequest request) { - this.waitingQueue.add(request); - } - - public Future connect(InetSocketAddressWrapper addressWrapper) - throws IOException { - if (addressWrapper == null) { - throw new NullPointerException("Null Address"); - } - // Remove addr from removed set - this.removedAddrSet.remove(addressWrapper.getInetSocketAddress()); - SocketChannel socketChannel = null; - try { - socketChannel = SocketChannel.open(); - this.configureSocketChannel(socketChannel); - ConnectFuture future = new ConnectFuture(addressWrapper); - if (!socketChannel.connect(addressWrapper.getInetSocketAddress())) { - this.selectorManager.registerChannel(socketChannel, - SelectionKey.OP_CONNECT, future); - } else { - this.addSession( - this.createSession(socketChannel, addressWrapper)); - future.setResult(true); - } - return future; - } catch (IOException e) { - if (socketChannel != null) { - socketChannel.close(); - } - throw e; - } - } - - public void closeChannel(Selector selector) throws IOException { - // do nothing - } - - private final Random random = new Random(); - - public Session send(final Command msg) throws MemcachedException { - MemcachedSession session = (MemcachedSession) this - .findSessionByKey(msg.getKey()); - if (session == null) { - throw new MemcachedException( - "There is no available connection at this moment"); - } - // If session was closed,try to use standby memcached node - if (session.isClosed()) { - session = this.findStandbySession(session); - } - if (session.isClosed()) { - throw new MemcachedException("Session(" - + SystemUtils - .getRawAddress(session.getRemoteSocketAddress()) - + ":" + session.getRemoteSocketAddress().getPort() - + ") has been closed"); - } - if (session.isAuthFailed()) { - throw new MemcachedException("Auth failed to connection " - + session.getRemoteSocketAddress()); - } - session.write(msg); - return session; - } - - private MemcachedSession findStandbySession(MemcachedSession session) { - if (this.failureMode) { - List sessionList = this - .getStandbySessionListByMainNodeAddr( - session.getRemoteSocketAddress()); - if (sessionList != null && !sessionList.isEmpty()) { - return (MemcachedTCPSession) sessionList - .get(this.random.nextInt(sessionList.size())); - } - } - return session; - } - - /** - * Returns main node's standby session list. - * - * @param addr - * @return - */ - public List getStandbySessionListByMainNodeAddr( - InetSocketAddress addr) { - return this.standbySessionMap.get(addr); - } - - private final SessionMonitor sessionMonitor = new SessionMonitor(); - - /** - * Inner state listenner,manage session monitor. - * - * @author boyan - * - */ - class InnerControllerStateListener implements ControllerStateListener { - - public void onAllSessionClosed(Controller controller) { - - } - - public void onException(Controller controller, Throwable t) { - log.error("Exception occured in controller", t); - } - - public void onReady(Controller controller) { - MemcachedConnector.this.sessionMonitor.setDaemon(true); - MemcachedConnector.this.sessionMonitor.start(); - } - - public void onStarted(Controller controller) { - - } - - public void onStopped(Controller controller) { - if (MemcachedConnector.this.sessionMonitor.isAlive()) { - MemcachedConnector.this.sessionMonitor.interrupt(); - } - } - - } - - public final Session findSessionByKey(String key) { - return this.sessionLocator.getSessionByKey(key); - } - - /** - * Get session by InetSocketAddress - * - * @param addr - * @return - */ - public final Queue getSessionByAddress(InetSocketAddress addr) { - return this.sessionMap.get(addr); - } - - public MemcachedConnector(Configuration configuration, - MemcachedSessionLocator locator, BufferAllocator allocator, - CommandFactory commandFactory, int poolSize, - int maxQueuedNoReplyOperations) { - super(configuration, null); - this.sessionLocator = locator; - this.protocol = commandFactory.getProtocol(); - this.addStateListener(new InnerControllerStateListener()); - this.updateSessions(); - this.bufferAllocator = allocator; - this.optimiezer = new Optimizer(this.protocol); - this.optimiezer.setBufferAllocator(this.bufferAllocator); - this.connectionPoolSize = poolSize; - this.soLingerOn = true; - this.commandFactory = commandFactory; - this.flowControl = new FlowControl(maxQueuedNoReplyOperations); - this.setSelectorPoolSize(configuration.getSelectorPoolSize()); - // setDispatchMessageThreadPoolSize(Runtime.getRuntime(). - // availableProcessors()); - } - - public final void setConnectionPoolSize(int poolSize) { - this.connectionPoolSize = poolSize; - } - - public void setMergeFactor(int mergeFactor) { - ((OptimizerMBean) this.optimiezer).setMergeFactor(mergeFactor); - } - - public FlowControl getNoReplyOpsFlowControl() { - return this.flowControl; - } - - @Override - protected NioSession buildSession(SocketChannel sc) { - Queue queue = this.buildQueue(); - final NioSessionConfig sessionCofig = this.buildSessionConfig(sc, - queue); - MemcachedTCPSession session = new MemcachedTCPSession(sessionCofig, - this.configuration.getSessionReadBufferSize(), this.optimiezer, - this.getReadThreadCount(), this.commandFactory); - session.setBufferAllocator(this.bufferAllocator); - return session; - } - - /** - * Build write queue for session - * - * @return - */ - @Override - protected Queue buildQueue() { - return new FlowControlLinkedTransferQueue(this.flowControl); - } - - public BufferAllocator getBufferAllocator() { - return this.bufferAllocator; - } - - public synchronized void quitAllSessions() { - for (Session session : this.sessionSet) { - ((MemcachedSession) session).quit(); - } - int sleepCount = 0; - while (sleepCount++ < 5 && this.sessionSet.size() > 0) { - try { - this.wait(1000); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - - } - - public void setFailureMode(boolean failureMode) { - this.failureMode = failureMode; - } - - public void setBufferAllocator(BufferAllocator allocator) { - this.bufferAllocator = allocator; - for (Session session : this.getSessionSet()) { - ((MemcachedSession) session).setBufferAllocator(allocator); - } - } - - public Collection getServerAddresses() { - return Collections.unmodifiableCollection(this.sessionMap.keySet()); - } -} +/** + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.impl; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.SocketChannel; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Queue; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.DelayQueue; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import net.rubyeye.xmemcached.CommandFactory; +import net.rubyeye.xmemcached.FlowControl; +import net.rubyeye.xmemcached.MemcachedClient; +import net.rubyeye.xmemcached.MemcachedOptimizer; +import net.rubyeye.xmemcached.MemcachedSessionLocator; +import net.rubyeye.xmemcached.buffer.BufferAllocator; +import net.rubyeye.xmemcached.command.Command; +import net.rubyeye.xmemcached.exception.MemcachedException; +import net.rubyeye.xmemcached.networking.Connector; +import net.rubyeye.xmemcached.networking.MemcachedSession; +import net.rubyeye.xmemcached.utils.InetSocketAddressWrapper; +import net.rubyeye.xmemcached.utils.Protocol; +import com.google.code.yanf4j.config.Configuration; +import com.google.code.yanf4j.core.Controller; +import com.google.code.yanf4j.core.ControllerStateListener; +import com.google.code.yanf4j.core.EventType; +import com.google.code.yanf4j.core.Session; +import com.google.code.yanf4j.core.WriteMessage; +import com.google.code.yanf4j.nio.NioSession; +import com.google.code.yanf4j.nio.NioSessionConfig; +import com.google.code.yanf4j.nio.impl.SocketChannelController; +import com.google.code.yanf4j.util.ConcurrentHashSet; +import com.google.code.yanf4j.util.SystemUtils; + +/** + * Connected session manager + * + * @author dennis + */ +public class MemcachedConnector extends SocketChannelController implements Connector { + private final DelayQueue waitingQueue = new DelayQueue(); + private BufferAllocator bufferAllocator; + + private final Set removedAddrSet = new ConcurrentHashSet(); + + private final MemcachedOptimizer optimiezer; + private long healSessionInterval = MemcachedClient.DEFAULT_HEAL_SESSION_INTERVAL; + private int connectionPoolSize; // session pool size + protected Protocol protocol; + private boolean enableHealSession = true; + private final CommandFactory commandFactory; + private boolean failureMode; + + private final ConcurrentHashMap/* + * standby + * sessions + */> standbySessionMap = + new ConcurrentHashMap>(); + + private final FlowControl flowControl; + + private volatile boolean shuttingDown = false; + + public void shuttingDown() { + this.shuttingDown = true; + } + + public void setSessionLocator(MemcachedSessionLocator sessionLocator) { + this.sessionLocator = sessionLocator; + } + + /** + * Session monitor for healing sessions. + * + * @author dennis + * + */ + class SessionMonitor extends Thread { + public SessionMonitor() { + this.setName("Heal-Session-Thread"); + } + + @Override + public void run() { + while (MemcachedConnector.this.isStarted() && MemcachedConnector.this.enableHealSession) { + ReconnectRequest request = null; + try { + request = MemcachedConnector.this.waitingQueue.take(); + + InetSocketAddress address = request.getInetSocketAddressWrapper().getInetSocketAddress(); + + if (!MemcachedConnector.this.removedAddrSet.contains(address)) { + boolean connected = false; + Future future = + MemcachedConnector.this.connect(request.getInetSocketAddressWrapper()); + request.setTries(request.getTries() + 1); + try { + log.info("Trying to connect to " + address.getAddress().getHostAddress() + ":" + + address.getPort() + " for " + request.getTries() + " times"); + if (!future.get(MemcachedClient.DEFAULT_CONNECT_TIMEOUT, TimeUnit.MILLISECONDS)) { + connected = false; + } else { + connected = true; + } + } catch (TimeoutException e) { + future.cancel(true); + } catch (ExecutionException e) { + future.cancel(true); + } finally { + if (!connected) { + this.rescheduleConnectRequest(request); + } else { + continue; + } + } + } else { + log.info("Remove invalid reconnect task for " + address); + // remove reconnect task + } + } catch (InterruptedException e) { + // ignore,check status + } catch (Exception e) { + log.error("SessionMonitor connect error", e); + this.rescheduleConnectRequest(request); + } + } + } + + private void rescheduleConnectRequest(ReconnectRequest request) { + if (request == null) { + return; + } + InetSocketAddress address = request.getInetSocketAddressWrapper().getInetSocketAddress(); + // update timestamp for next reconnecting + request.updateNextReconnectTimeStamp( + MemcachedConnector.this.healSessionInterval * request.getTries()); + log.error("Reconnected to " + address + " fail"); + // add to tail + MemcachedConnector.this.waitingQueue.offer(request); + } + } + + public void setEnableHealSession(boolean enableHealSession) { + this.enableHealSession = enableHealSession; + // wake up session monitor thread. + if (this.sessionMonitor != null && this.sessionMonitor.isAlive()) { + this.sessionMonitor.interrupt(); + } + } + + public Queue getReconnectRequestQueue() { + return this.waitingQueue; + } + + @Override + public Set getSessionSet() { + Collection> sessionQueues = this.sessionMap.values(); + Set result = new HashSet(); + for (Queue queue : sessionQueues) { + result.addAll(queue); + } + return result; + } + + public final void setHealSessionInterval(long healConnectionInterval) { + this.healSessionInterval = healConnectionInterval; + } + + public long getHealSessionInterval() { + return this.healSessionInterval; + } + + public void setOptimizeGet(boolean optimiezeGet) { + ((OptimizerMBean) this.optimiezer).setOptimizeGet(optimiezeGet); + } + + public void setOptimizeMergeBuffer(boolean optimizeMergeBuffer) { + ((OptimizerMBean) this.optimiezer).setOptimizeMergeBuffer(optimizeMergeBuffer); + } + + public Protocol getProtocol() { + return this.protocol; + } + + protected MemcachedSessionLocator sessionLocator; + + protected final ConcurrentHashMap> sessionMap = + new ConcurrentHashMap>(); + + public synchronized void addSession(Session session) { + MemcachedSession tcpSession = (MemcachedSession) session; + + InetSocketAddressWrapper addrWrapper = tcpSession.getInetSocketAddressWrapper(); + // Remember the first time address resolved and use it in all + // application lifecycle. + if (addrWrapper.getRemoteAddressStr() == null) { + addrWrapper.setRemoteAddressStr(String.valueOf(session.getRemoteSocketAddress())); + } + + InetSocketAddress mainNodeAddress = addrWrapper.getMainNodeAddress(); + if (mainNodeAddress != null) { + // It is a standby session + this.addStandbySession(session, mainNodeAddress, + addrWrapper.getResolvedMainNodeSocketAddress(), addrWrapper); + } else { + // It is a main session + this.addMainSession(session, addrWrapper.getResolvedSocketAddress(), addrWrapper); + // Update main sessions + this.updateSessions(); + } + } + + private void addMainSession(Session session, InetSocketAddress lastReolvedAddr, + InetSocketAddressWrapper addrWrapper) { + InetSocketAddress remoteSocketAddress = session.getRemoteSocketAddress(); + log.info("Add a session: " + SystemUtils.getRawAddress(remoteSocketAddress) + ":" + + remoteSocketAddress.getPort()); + if (lastReolvedAddr != null && !lastReolvedAddr.equals(remoteSocketAddress)) { + log.warn("Memcached node {} is resolved into {}.", lastReolvedAddr, remoteSocketAddress); + // Remove and closed old resolved address. + Queue sessions = sessionMap.remove(lastReolvedAddr); + if (sessions != null) { + for (Session s : sessions) { + ((MemcachedSession) s).setAllowReconnect(false); + s.close(); + } + } + // updated resolve addr + addrWrapper.setResolvedSocketAddress(remoteSocketAddress); + } + Queue sessions = this.sessionMap.get(remoteSocketAddress); + if (sessions == null) { + sessions = new ConcurrentLinkedQueue(); + Queue oldSessions = this.sessionMap.putIfAbsent(remoteSocketAddress, sessions); + if (null != oldSessions) { + sessions = oldSessions; + } + } + // If it is in failure mode,remove closed session from list + if (this.failureMode) { + Iterator it = sessions.iterator(); + while (it.hasNext()) { + Session tmp = it.next(); + if (tmp.isClosed()) { + it.remove(); + break; + } + } + } + + sessions.offer(session); + // Remove old session and close it + while (sessions.size() > this.connectionPoolSize) { + Session oldSession = sessions.poll(); + ((MemcachedSession) oldSession).setAllowReconnect(false); + oldSession.close(); + } + } + + private void addStandbySession(Session session, InetSocketAddress mainNodeAddress, + InetSocketAddress lastResolvedMainAddr, InetSocketAddressWrapper addrWrapper) { + InetSocketAddress remoteSocketAddress = session.getRemoteSocketAddress(); + log.info("Add a standby session: " + SystemUtils.getRawAddress(remoteSocketAddress) + ":" + + remoteSocketAddress.getPort() + " for " + SystemUtils.getRawAddress(mainNodeAddress) + ":" + + mainNodeAddress.getPort()); + if (lastResolvedMainAddr != null && !lastResolvedMainAddr.equals(remoteSocketAddress)) { + log.warn("Memcached node {} is resolved into {}.", lastResolvedMainAddr, remoteSocketAddress); + // Remove and closed old resolved address. + List sessions = standbySessionMap.remove(lastResolvedMainAddr); + if (sessions != null) { + for (Session s : sessions) { + ((MemcachedSession) s).setAllowReconnect(false); + s.close(); + } + } + addrWrapper.setResolvedMainNodeSocketAddress(remoteSocketAddress); + } + List sessions = this.standbySessionMap.get(mainNodeAddress); + if (sessions == null) { + sessions = new CopyOnWriteArrayList(); + List oldSessions = this.standbySessionMap.putIfAbsent(mainNodeAddress, sessions); + if (null != oldSessions) { + sessions = oldSessions; + } + } + sessions.add(session); + } + + public List getSessionListBySocketAddress(InetSocketAddress inetSocketAddress) { + Queue queue = this.sessionMap.get(inetSocketAddress); + if (queue != null) { + return new ArrayList(queue); + } else { + return null; + } + } + + public void removeReconnectRequest(InetSocketAddress inetSocketAddress) { + this.removedAddrSet.add(inetSocketAddress); + Iterator it = this.waitingQueue.iterator(); + while (it.hasNext()) { + ReconnectRequest request = it.next(); + if (request.getInetSocketAddressWrapper().getInetSocketAddress().equals(inetSocketAddress)) { + it.remove(); + log.warn("Remove invalid reconnect task for " + + request.getInetSocketAddressWrapper().getInetSocketAddress()); + } + } + } + + private static final MemcachedSessionComparator sessionComparator = + new MemcachedSessionComparator(); + + public final void updateSessions() { + Collection> sessionCollection = this.sessionMap.values(); + List sessionList = new ArrayList(20); + for (Queue sessions : sessionCollection) { + sessionList.addAll(sessions); + } + // sort the sessions to keep order + Collections.sort(sessionList, sessionComparator); + this.sessionLocator.updateSessions(sessionList); + } + + public synchronized void removeSession(Session session) { + MemcachedTCPSession tcpSession = (MemcachedTCPSession) session; + InetSocketAddressWrapper addrWrapper = tcpSession.getInetSocketAddressWrapper(); + InetSocketAddress mainNodeAddr = addrWrapper.getMainNodeAddress(); + if (mainNodeAddr != null) { + this.removeStandbySession(session, mainNodeAddr); + } else { + this.removeMainSession(session); + } + } + + private void removeMainSession(Session session) { + InetSocketAddress remoteSocketAddress = session.getRemoteSocketAddress(); + // If it was in failure mode,we don't remove closed session from list. + if (this.failureMode && ((MemcachedSession) session).isAllowReconnect() && !this.shuttingDown + && this.isStarted()) { + log.warn("Client in failure mode,we don't remove session " + + SystemUtils.getRawAddress(remoteSocketAddress) + ":" + remoteSocketAddress.getPort()); + return; + } + log.info("Remove a session: " + SystemUtils.getRawAddress(remoteSocketAddress) + ":" + + remoteSocketAddress.getPort()); + Queue sessionQueue = this.sessionMap.get(session.getRemoteSocketAddress()); + if (null != sessionQueue) { + sessionQueue.remove(session); + if (sessionQueue.size() == 0) { + this.sessionMap.remove(session.getRemoteSocketAddress()); + } + this.updateSessions(); + } + } + + private void removeStandbySession(Session session, InetSocketAddress mainNodeAddr) { + List sessionList = this.standbySessionMap.get(mainNodeAddr); + if (null != sessionList) { + sessionList.remove(session); + if (sessionList.size() == 0) { + this.standbySessionMap.remove(mainNodeAddr); + } + } + } + + @Override + protected void doStart() throws IOException { + this.setLocalSocketAddress(new InetSocketAddress("localhost", 0)); + } + + @Override + public void onConnect(SelectionKey key) throws IOException { + key.interestOps(key.interestOps() & ~SelectionKey.OP_CONNECT); + ConnectFuture future = (ConnectFuture) key.attachment(); + if (future == null || future.isCancelled()) { + this.cancelKey(key); + return; + } + try { + if (!((SocketChannel) key.channel()).finishConnect()) { + this.cancelKey(key); + future + .failure(new IOException("Connect to " + + SystemUtils.getRawAddress( + future.getInetSocketAddressWrapper().getInetSocketAddress()) + + ":" + future.getInetSocketAddressWrapper().getInetSocketAddress().getPort() + + " fail")); + } else { + key.attach(null); + this.addSession(this.createSession((SocketChannel) key.channel(), + future.getInetSocketAddressWrapper())); + future.setResult(Boolean.TRUE); + } + } catch (Exception e) { + future.failure(e); + this.cancelKey(key); + throw new IOException("Connect to " + + SystemUtils.getRawAddress(future.getInetSocketAddressWrapper().getInetSocketAddress()) + + ":" + future.getInetSocketAddressWrapper().getInetSocketAddress().getPort() + " fail," + + e.getMessage()); + } + } + + private void cancelKey(SelectionKey key) throws IOException { + try { + if (key.channel() != null) { + key.channel().close(); + } + } finally { + key.cancel(); + } + } + + protected MemcachedTCPSession createSession(SocketChannel socketChannel, + InetSocketAddressWrapper wrapper) { + MemcachedTCPSession session = (MemcachedTCPSession) this.buildSession(socketChannel); + session.setInetSocketAddressWrapper(wrapper); + this.selectorManager.registerSession(session, EventType.ENABLE_READ); + session.start(); + session.onEvent(EventType.CONNECTED, null); + return session; + } + + public void addToWatingQueue(ReconnectRequest request) { + this.waitingQueue.add(request); + } + + public Future connect(InetSocketAddressWrapper addressWrapper) throws IOException { + if (addressWrapper == null) { + throw new NullPointerException("Null Address"); + } + // Remove addr from removed set + this.removedAddrSet.remove(addressWrapper.getInetSocketAddress()); + SocketChannel socketChannel = null; + try { + socketChannel = SocketChannel.open(); + this.configureSocketChannel(socketChannel); + ConnectFuture future = new ConnectFuture(addressWrapper); + if (!socketChannel.connect(addressWrapper.getInetSocketAddress())) { + this.selectorManager.registerChannel(socketChannel, SelectionKey.OP_CONNECT, future); + } else { + this.addSession(this.createSession(socketChannel, addressWrapper)); + future.setResult(true); + } + return future; + } catch (IOException e) { + if (socketChannel != null) { + socketChannel.close(); + } + throw e; + } + } + + public void closeChannel(Selector selector) throws IOException { + // do nothing + } + + private final Random random = new Random(); + + public Session send(final Command msg) throws MemcachedException { + MemcachedSession session = (MemcachedSession) this.findSessionByKey(msg.getKey()); + if (session == null) { + throw new MemcachedException("There is no available connection at this moment"); + } + // If session was closed,try to use standby memcached node + if (session.isClosed()) { + session = this.findStandbySession(session); + } + if (session.isClosed()) { + throw new MemcachedException( + "Session(" + SystemUtils.getRawAddress(session.getRemoteSocketAddress()) + ":" + + session.getRemoteSocketAddress().getPort() + ") has been closed"); + } + if (session.isAuthFailed()) { + throw new MemcachedException("Auth failed to connection " + session.getRemoteSocketAddress()); + } + session.write(msg); + return session; + } + + private MemcachedSession findStandbySession(MemcachedSession session) { + if (this.failureMode) { + List sessionList = + this.getStandbySessionListByMainNodeAddr(session.getRemoteSocketAddress()); + if (sessionList != null && !sessionList.isEmpty()) { + return (MemcachedTCPSession) sessionList.get(this.random.nextInt(sessionList.size())); + } + } + return session; + } + + /** + * Returns main node's standby session list. + * + * @param addr + * @return + */ + public List getStandbySessionListByMainNodeAddr(InetSocketAddress addr) { + return this.standbySessionMap.get(addr); + } + + private final SessionMonitor sessionMonitor = new SessionMonitor(); + + /** + * Inner state listenner,manage session monitor. + * + * @author boyan + * + */ + class InnerControllerStateListener implements ControllerStateListener { + + public void onAllSessionClosed(Controller controller) { + + } + + public void onException(Controller controller, Throwable t) { + log.error("Exception occured in controller", t); + } + + public void onReady(Controller controller) { + MemcachedConnector.this.sessionMonitor.setDaemon(true); + MemcachedConnector.this.sessionMonitor.start(); + } + + public void onStarted(Controller controller) { + + } + + public void onStopped(Controller controller) { + if (MemcachedConnector.this.sessionMonitor.isAlive()) { + MemcachedConnector.this.sessionMonitor.interrupt(); + } + } + + } + + public final Session findSessionByKey(String key) { + return this.sessionLocator.getSessionByKey(key); + } + + /** + * Get session by InetSocketAddress + * + * @param addr + * @return + */ + public final Queue getSessionByAddress(InetSocketAddress addr) { + return this.sessionMap.get(addr); + } + + public MemcachedConnector(Configuration configuration, MemcachedSessionLocator locator, + BufferAllocator allocator, CommandFactory commandFactory, int poolSize, + int maxQueuedNoReplyOperations) { + super(configuration, null); + this.sessionLocator = locator; + this.protocol = commandFactory.getProtocol(); + this.addStateListener(new InnerControllerStateListener()); + this.updateSessions(); + this.bufferAllocator = allocator; + this.optimiezer = new Optimizer(this.protocol); + this.optimiezer.setBufferAllocator(this.bufferAllocator); + this.connectionPoolSize = poolSize; + this.soLingerOn = true; + this.commandFactory = commandFactory; + this.flowControl = new FlowControl(maxQueuedNoReplyOperations); + this.setSelectorPoolSize(configuration.getSelectorPoolSize()); + // setDispatchMessageThreadPoolSize(Runtime.getRuntime(). + // availableProcessors()); + } + + public final void setConnectionPoolSize(int poolSize) { + this.connectionPoolSize = poolSize; + } + + public void setMergeFactor(int mergeFactor) { + ((OptimizerMBean) this.optimiezer).setMergeFactor(mergeFactor); + } + + public FlowControl getNoReplyOpsFlowControl() { + return this.flowControl; + } + + @Override + protected NioSession buildSession(SocketChannel sc) { + Queue queue = this.buildQueue(); + final NioSessionConfig sessionCofig = this.buildSessionConfig(sc, queue); + MemcachedTCPSession session = + new MemcachedTCPSession(sessionCofig, this.configuration.getSessionReadBufferSize(), + this.optimiezer, this.getReadThreadCount(), this.commandFactory); + session.setBufferAllocator(this.bufferAllocator); + return session; + } + + /** + * Build write queue for session + * + * @return + */ + @Override + protected Queue buildQueue() { + return new FlowControlLinkedTransferQueue(this.flowControl); + } + + public BufferAllocator getBufferAllocator() { + return this.bufferAllocator; + } + + public synchronized void quitAllSessions() { + for (Session session : this.sessionSet) { + ((MemcachedSession) session).quit(); + } + int sleepCount = 0; + while (sleepCount++ < 5 && this.sessionSet.size() > 0) { + try { + this.wait(1000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + } + + public void setFailureMode(boolean failureMode) { + this.failureMode = failureMode; + } + + public void setBufferAllocator(BufferAllocator allocator) { + this.bufferAllocator = allocator; + for (Session session : this.getSessionSet()) { + ((MemcachedSession) session).setBufferAllocator(allocator); + } + } + + public Collection getServerAddresses() { + return Collections.unmodifiableCollection(this.sessionMap.keySet()); + } +} diff --git a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java index feb18bd33..299d19a5e 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedHandler.java @@ -1,13 +1,10 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.impl; @@ -16,7 +13,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; - import net.rubyeye.xmemcached.MemcachedClient; import net.rubyeye.xmemcached.MemcachedClientStateListener; import net.rubyeye.xmemcached.auth.AuthMemcachedConnectListener; @@ -35,10 +31,8 @@ import net.rubyeye.xmemcached.transcoders.CachedData; import net.rubyeye.xmemcached.utils.InetSocketAddressWrapper; import net.rubyeye.xmemcached.utils.Protocol; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import com.google.code.yanf4j.buffer.IoBuffer; import com.google.code.yanf4j.core.Session; import com.google.code.yanf4j.core.impl.AbstractSession; @@ -49,278 +43,251 @@ import java.util.concurrent.ThreadPoolExecutor; /** - * Memcached Session Handler,used for dispatching commands and session's - * lifecycle management + * Memcached Session Handler,used for dispatching commands and session's lifecycle management * * @author dennis * */ public class MemcachedHandler extends HandlerAdapter { - private static final int MAX_HEARTBEAT_THREADS = Integer - .parseInt(System.getProperty("xmemcached.heartbeat.max_threads", - String.valueOf(SystemUtils.getSystemThreadCount()))); - - private final StatisticsHandler statisticsHandler; - - private ExecutorService heartBeatThreadPool; - - private final MemcachedSessionConnectListener listener; - - private final MemcachedClient client; - private static final Logger log = LoggerFactory - .getLogger(MemcachedHandler.class); - - /** - * On receive message from memcached server - */ - @Override - public final void onMessageReceived(final Session session, - final Object msg) { - Command command = (Command) msg; - if (this.statisticsHandler.isStatistics()) { - if (command.getCopiedMergeCount() > 0 - && command instanceof MapReturnValueAware) { - Map returnValues = ((MapReturnValueAware) command) - .getReturnValues(); - int size = returnValues.size(); - this.statisticsHandler.statistics(CommandType.GET_HIT, size); - this.statisticsHandler.statistics(CommandType.GET_MISS, - command.getCopiedMergeCount() - size); - } else if (command instanceof TextGetOneCommand - || command instanceof BinaryGetCommand) { - if (command.getResult() != null) { - this.statisticsHandler.statistics(CommandType.GET_HIT); - } else { - this.statisticsHandler.statistics(CommandType.GET_MISS); - } - } else { - if (command.getCopiedMergeCount() > 0) { - this.statisticsHandler.statistics(command.getCommandType(), - command.getCopiedMergeCount()); - } else - this.statisticsHandler.statistics(command.getCommandType()); - } - } - } - - private volatile boolean enableHeartBeat = true; - - public void setEnableHeartBeat(boolean enableHeartBeat) { - this.enableHeartBeat = enableHeartBeat; - } - - public static final IoBuffer EMPTY_BUF = IoBuffer.allocate(0); - - /** - * put command which have been sent to queue - */ - @Override - public final void onMessageSent(Session session, Object msg) { - Command command = (Command) msg; - command.setStatus(OperationStatus.SENT); - // After message sent,we can set the buffer to be null for gc friendly. - command.setIoBuffer(EMPTY_BUF); - switch (command.getCommandType()) { - case ADD : - case APPEND : - case SET : - case SET_MANY : - // After message sent,we can set the value to be null for gc - // friendly. - if (command instanceof StoreCommand) { - ((StoreCommand) command).setValue(null); - } - break; - } - } - - @Override - public void onExceptionCaught(Session session, Throwable throwable) { - log.error("XMemcached network layout exception", throwable); - } - - /** - * On session started - */ - @Override - public void onSessionStarted(Session session) { - session.setUseBlockingRead(true); - session.setAttribute(HEART_BEAT_FAIL_COUNT_ATTR, new AtomicInteger(0)); - for (MemcachedClientStateListener listener : this.client - .getStateListeners()) { - listener.onConnected(this.client, session.getRemoteSocketAddress()); - } - this.listener.onConnect((MemcachedTCPSession) session, this.client); - } - - /** - * Check if have to reconnect on session closed - */ - @Override - public final void onSessionClosed(Session session) { - this.client.getConnector().removeSession(session); - // Clear write queue to release noreply operations. - ((AbstractSession) session).clearWriteQueue(); - MemcachedTCPSession memcachedSession = (MemcachedTCPSession) session; - // destroy memached session - memcachedSession.destroy(); - if (this.client.getConnector().isStarted() - && memcachedSession.isAllowReconnect()) { - this.reconnect(memcachedSession); - } - for (MemcachedClientStateListener listener : this.client - .getStateListeners()) { - listener.onDisconnected(this.client, - session.getRemoteSocketAddress()); - } - - } - - /** - * Do a heartbeat action - */ - @Override - public void onSessionIdle(Session session) { - checkHeartBeat(session); - } - - private void checkHeartBeat(Session session) { - if (this.enableHeartBeat) { - log.debug("Check session ({}) is alive,send heartbeat", - session.getRemoteSocketAddress() == null - ? "unknown" - : SystemUtils.getRawAddress( - session.getRemoteSocketAddress()) + ":" - + session.getRemoteSocketAddress() - .getPort()); - Command versionCommand = null; - CountDownLatch latch = new CountDownLatch(1); - if (this.client.getProtocol() == Protocol.Binary) { - versionCommand = new BinaryVersionCommand(latch, - session.getRemoteSocketAddress()); - - } else { - versionCommand = new TextVersionCommand(latch, - session.getRemoteSocketAddress()); - } - session.write(versionCommand); - // Start a check thread,avoid blocking reactor thread - if (this.heartBeatThreadPool != null) { - this.heartBeatThreadPool.execute( - new CheckHeartResultThread(versionCommand, session)); - } - } - } - - private static final String HEART_BEAT_FAIL_COUNT_ATTR = "heartBeatFailCount"; - private static final int MAX_HEART_BEAT_FAIL_COUNT = Integer.parseInt( - System.getProperty("xmemcached.heartbeat.max.fail.times", "3")); - - final static class CheckHeartResultThread implements Runnable { - - private final Command versionCommand; - private final Session session; - - public CheckHeartResultThread(Command versionCommand, Session session) { - super(); - this.versionCommand = versionCommand; - this.session = session; - } - - public void run() { - try { - AtomicInteger heartBeatFailCount = (AtomicInteger) this.session - .getAttribute(HEART_BEAT_FAIL_COUNT_ATTR); - if (heartBeatFailCount != null) { - if (!this.versionCommand.getLatch().await(2000, - TimeUnit.MILLISECONDS)) { - heartBeatFailCount.incrementAndGet(); - } else { - if (this.versionCommand.getResult() == null) { - heartBeatFailCount.incrementAndGet(); - } else { - // reset the failure counter - heartBeatFailCount.set(0); - } - } - if (heartBeatFailCount.get() > MAX_HEART_BEAT_FAIL_COUNT) { - log.warn("Session(" - + SystemUtils.getRawAddress( - this.session.getRemoteSocketAddress()) - + ":" - + this.session.getRemoteSocketAddress() - .getPort() - + ") heartbeat fail " + heartBeatFailCount.get() - + " times,close session and try to heal it"); - this.session.close();// close session - heartBeatFailCount.set(0); - } - } - } catch (InterruptedException e) { - // ignore - } - } - } - - /** - * Auto reconect to memcached server - * - * @param session - */ - protected void reconnect(MemcachedTCPSession session) { - if (!this.client.isShutdown()) { - // Prevent reconnecting repeatedly - synchronized (session) { - if (!session.isAllowReconnect()) { - return; - } - session.setAllowReconnect(false); - } - MemcachedSession memcachedTCPSession = session; - InetSocketAddressWrapper inetSocketAddressWrapper = memcachedTCPSession - .getInetSocketAddressWrapper(); - this.client.getConnector().addToWatingQueue( - new ReconnectRequest(inetSocketAddressWrapper, 0, - this.client.getHealSessionInterval())); - } - } - - public void stop() { - this.heartBeatThreadPool.shutdown(); - } - - final long HEARTBEAT_PERIOD = Long.parseLong( - System.getProperty("xmemcached.heartbeat.period", "5000")); - - public void start() { - final String name = "XMemcached-HeartBeatPool[" + client.getName() - + "]"; - final AtomicInteger threadCounter = new AtomicInteger(); - - long keepAliveTime = client.getConnector().getSessionIdleTimeout() * 3 - / 2; - - this.heartBeatThreadPool = new ThreadPoolExecutor(1, - MAX_HEARTBEAT_THREADS, keepAliveTime, TimeUnit.MILLISECONDS, - new SynchronousQueue(), new ThreadFactory() { - public Thread newThread(Runnable r) { - Thread t = new Thread(r, - name + "-" + threadCounter.getAndIncrement()); - t.setDaemon(true); - if (t.getPriority() != Thread.NORM_PRIORITY) { - t.setPriority(Thread.NORM_PRIORITY); - } - return t; - } - }, new ThreadPoolExecutor.DiscardPolicy()); - } - - public MemcachedHandler(MemcachedClient client) { - super(); - this.client = client; - this.listener = new AuthMemcachedConnectListener(); - this.statisticsHandler = new StatisticsHandler(); - } + private static final int MAX_HEARTBEAT_THREADS = + Integer.parseInt(System.getProperty("xmemcached.heartbeat.max_threads", + String.valueOf(SystemUtils.getSystemThreadCount()))); + + private final StatisticsHandler statisticsHandler; + + private ExecutorService heartBeatThreadPool; + + private final MemcachedSessionConnectListener listener; + + private final MemcachedClient client; + private static final Logger log = LoggerFactory.getLogger(MemcachedHandler.class); + + /** + * On receive message from memcached server + */ + @Override + public final void onMessageReceived(final Session session, final Object msg) { + Command command = (Command) msg; + if (this.statisticsHandler.isStatistics()) { + if (command.getCopiedMergeCount() > 0 && command instanceof MapReturnValueAware) { + Map returnValues = ((MapReturnValueAware) command).getReturnValues(); + int size = returnValues.size(); + this.statisticsHandler.statistics(CommandType.GET_HIT, size); + this.statisticsHandler.statistics(CommandType.GET_MISS, + command.getCopiedMergeCount() - size); + } else if (command instanceof TextGetOneCommand || command instanceof BinaryGetCommand) { + if (command.getResult() != null) { + this.statisticsHandler.statistics(CommandType.GET_HIT); + } else { + this.statisticsHandler.statistics(CommandType.GET_MISS); + } + } else { + if (command.getCopiedMergeCount() > 0) { + this.statisticsHandler.statistics(command.getCommandType(), + command.getCopiedMergeCount()); + } else + this.statisticsHandler.statistics(command.getCommandType()); + } + } + } + + private volatile boolean enableHeartBeat = true; + + public void setEnableHeartBeat(boolean enableHeartBeat) { + this.enableHeartBeat = enableHeartBeat; + } + + public static final IoBuffer EMPTY_BUF = IoBuffer.allocate(0); + + /** + * put command which have been sent to queue + */ + @Override + public final void onMessageSent(Session session, Object msg) { + Command command = (Command) msg; + command.setStatus(OperationStatus.SENT); + // After message sent,we can set the buffer to be null for gc friendly. + command.setIoBuffer(EMPTY_BUF); + switch (command.getCommandType()) { + case ADD: + case APPEND: + case SET: + case SET_MANY: + // After message sent,we can set the value to be null for gc + // friendly. + if (command instanceof StoreCommand) { + ((StoreCommand) command).setValue(null); + } + break; + } + } + + @Override + public void onExceptionCaught(Session session, Throwable throwable) { + log.error("XMemcached network layout exception", throwable); + } + + /** + * On session started + */ + @Override + public void onSessionStarted(Session session) { + session.setUseBlockingRead(true); + session.setAttribute(HEART_BEAT_FAIL_COUNT_ATTR, new AtomicInteger(0)); + for (MemcachedClientStateListener listener : this.client.getStateListeners()) { + listener.onConnected(this.client, session.getRemoteSocketAddress()); + } + this.listener.onConnect((MemcachedTCPSession) session, this.client); + } + + /** + * Check if have to reconnect on session closed + */ + @Override + public final void onSessionClosed(Session session) { + this.client.getConnector().removeSession(session); + // Clear write queue to release noreply operations. + ((AbstractSession) session).clearWriteQueue(); + MemcachedTCPSession memcachedSession = (MemcachedTCPSession) session; + // destroy memached session + memcachedSession.destroy(); + if (this.client.getConnector().isStarted() && memcachedSession.isAllowReconnect()) { + this.reconnect(memcachedSession); + } + for (MemcachedClientStateListener listener : this.client.getStateListeners()) { + listener.onDisconnected(this.client, session.getRemoteSocketAddress()); + } + + } + + /** + * Do a heartbeat action + */ + @Override + public void onSessionIdle(Session session) { + checkHeartBeat(session); + } + + private void checkHeartBeat(Session session) { + if (this.enableHeartBeat) { + log.debug("Check session ({}) is alive,send heartbeat", + session.getRemoteSocketAddress() == null ? "unknown" + : SystemUtils.getRawAddress(session.getRemoteSocketAddress()) + ":" + + session.getRemoteSocketAddress().getPort()); + Command versionCommand = null; + CountDownLatch latch = new CountDownLatch(1); + if (this.client.getProtocol() == Protocol.Binary) { + versionCommand = new BinaryVersionCommand(latch, session.getRemoteSocketAddress()); + + } else { + versionCommand = new TextVersionCommand(latch, session.getRemoteSocketAddress()); + } + session.write(versionCommand); + // Start a check thread,avoid blocking reactor thread + if (this.heartBeatThreadPool != null) { + this.heartBeatThreadPool.execute(new CheckHeartResultThread(versionCommand, session)); + } + } + } + + private static final String HEART_BEAT_FAIL_COUNT_ATTR = "heartBeatFailCount"; + private static final int MAX_HEART_BEAT_FAIL_COUNT = + Integer.parseInt(System.getProperty("xmemcached.heartbeat.max.fail.times", "3")); + + final static class CheckHeartResultThread implements Runnable { + + private final Command versionCommand; + private final Session session; + + public CheckHeartResultThread(Command versionCommand, Session session) { + super(); + this.versionCommand = versionCommand; + this.session = session; + } + + public void run() { + try { + AtomicInteger heartBeatFailCount = + (AtomicInteger) this.session.getAttribute(HEART_BEAT_FAIL_COUNT_ATTR); + if (heartBeatFailCount != null) { + if (!this.versionCommand.getLatch().await(2000, TimeUnit.MILLISECONDS)) { + heartBeatFailCount.incrementAndGet(); + } else { + if (this.versionCommand.getResult() == null) { + heartBeatFailCount.incrementAndGet(); + } else { + // reset the failure counter + heartBeatFailCount.set(0); + } + } + if (heartBeatFailCount.get() > MAX_HEART_BEAT_FAIL_COUNT) { + log.warn("Session(" + SystemUtils.getRawAddress(this.session.getRemoteSocketAddress()) + + ":" + this.session.getRemoteSocketAddress().getPort() + ") heartbeat fail " + + heartBeatFailCount.get() + " times,close session and try to heal it"); + this.session.close();// close session + heartBeatFailCount.set(0); + } + } + } catch (InterruptedException e) { + // ignore + } + } + } + + /** + * Auto reconect to memcached server + * + * @param session + */ + protected void reconnect(MemcachedTCPSession session) { + if (!this.client.isShutdown()) { + // Prevent reconnecting repeatedly + synchronized (session) { + if (!session.isAllowReconnect()) { + return; + } + session.setAllowReconnect(false); + } + MemcachedSession memcachedTCPSession = session; + InetSocketAddressWrapper inetSocketAddressWrapper = + memcachedTCPSession.getInetSocketAddressWrapper(); + this.client.getConnector().addToWatingQueue( + new ReconnectRequest(inetSocketAddressWrapper, 0, this.client.getHealSessionInterval())); + } + } + + public void stop() { + this.heartBeatThreadPool.shutdown(); + } + + final long HEARTBEAT_PERIOD = + Long.parseLong(System.getProperty("xmemcached.heartbeat.period", "5000")); + + public void start() { + final String name = "XMemcached-HeartBeatPool[" + client.getName() + "]"; + final AtomicInteger threadCounter = new AtomicInteger(); + + long keepAliveTime = client.getConnector().getSessionIdleTimeout() * 3 / 2; + + this.heartBeatThreadPool = new ThreadPoolExecutor(1, MAX_HEARTBEAT_THREADS, keepAliveTime, + TimeUnit.MILLISECONDS, new SynchronousQueue(), new ThreadFactory() { + public Thread newThread(Runnable r) { + Thread t = new Thread(r, name + "-" + threadCounter.getAndIncrement()); + t.setDaemon(true); + if (t.getPriority() != Thread.NORM_PRIORITY) { + t.setPriority(Thread.NORM_PRIORITY); + } + return t; + } + }, new ThreadPoolExecutor.DiscardPolicy()); + } + + public MemcachedHandler(MemcachedClient client) { + super(); + this.client = client; + this.listener = new AuthMemcachedConnectListener(); + this.statisticsHandler = new StatisticsHandler(); + } } diff --git a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedSessionComparator.java b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedSessionComparator.java index 1f3556a7d..9afb80f13 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedSessionComparator.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedSessionComparator.java @@ -2,9 +2,7 @@ import java.io.Serializable; import java.util.Comparator; - import net.rubyeye.xmemcached.networking.MemcachedSession; - import com.google.code.yanf4j.core.Session; /** @@ -13,23 +11,20 @@ * @author dennis * */ -public class MemcachedSessionComparator - implements - Comparator, - Serializable { - static final long serialVersionUID = -1L; +public class MemcachedSessionComparator implements Comparator, Serializable { + static final long serialVersionUID = -1L; - public int compare(Session o1, Session o2) { - MemcachedSession session1 = (MemcachedSession) o1; - MemcachedSession session2 = (MemcachedSession) o2; - if (session1 == null) { - return -1; - } - if (session2 == null) { - return 1; - } - return session1.getInetSocketAddressWrapper().getOrder() - - session2.getInetSocketAddressWrapper().getOrder(); - } + public int compare(Session o1, Session o2) { + MemcachedSession session1 = (MemcachedSession) o1; + MemcachedSession session2 = (MemcachedSession) o2; + if (session1 == null) { + return -1; + } + if (session2 == null) { + return 1; + } + return session1.getInetSocketAddressWrapper().getOrder() + - session2.getInetSocketAddressWrapper().getOrder(); + } } diff --git a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedTCPSession.java b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedTCPSession.java index 7a44a34e8..0ceae8689 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/MemcachedTCPSession.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/MemcachedTCPSession.java @@ -1,243 +1,228 @@ -/** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 net.rubyeye.xmemcached.impl; - -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.net.SocketException; -import java.nio.channels.SocketChannel; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Future; -import java.util.concurrent.atomic.AtomicReference; - -import net.rubyeye.xmemcached.CommandFactory; -import net.rubyeye.xmemcached.MemcachedOptimizer; -import net.rubyeye.xmemcached.buffer.BufferAllocator; -import net.rubyeye.xmemcached.command.Command; -import net.rubyeye.xmemcached.command.OperationStatus; -import net.rubyeye.xmemcached.exception.MemcachedException; -import net.rubyeye.xmemcached.networking.MemcachedSession; -import net.rubyeye.xmemcached.utils.InetSocketAddressWrapper; -import net.rubyeye.xmemcached.utils.Protocol; - -import com.google.code.yanf4j.core.WriteMessage; -import com.google.code.yanf4j.core.impl.FutureImpl; -import com.google.code.yanf4j.nio.NioSessionConfig; -import com.google.code.yanf4j.nio.impl.NioTCPSession; -import com.google.code.yanf4j.util.LinkedTransferQueue; -import com.google.code.yanf4j.util.SystemUtils; - -/** - * Connected session for a memcached server - * - * @author dennis - */ -public class MemcachedTCPSession extends NioTCPSession - implements - MemcachedSession { - - /** - * Command which are already sent - */ - protected BlockingQueue commandAlreadySent; - - private final AtomicReference currentCommand = new LinkedTransferQueue.PaddedAtomicReference( - null); - - private SocketAddress remoteSocketAddress; // prevent channel is closed - private int sendBufferSize; - private final MemcachedOptimizer optimiezer; - private boolean allowReconnect; - - private volatile boolean authFailed; - - private final CommandFactory commandFactory; - - private InetSocketAddressWrapper inetSocketAddressWrapper; - - public MemcachedTCPSession(NioSessionConfig sessionConfig, - int readRecvBufferSize, MemcachedOptimizer optimiezer, - int readThreadCount, CommandFactory commandFactory) { - super(sessionConfig, readRecvBufferSize); - this.optimiezer = optimiezer; - if (this.selectableChannel != null) { - this.remoteSocketAddress = ((SocketChannel) this.selectableChannel) - .socket().getRemoteSocketAddress(); - this.allowReconnect = true; - try { - this.sendBufferSize = ((SocketChannel) this.selectableChannel) - .socket().getSendBufferSize(); - } catch (SocketException e) { - this.sendBufferSize = 8 * 1024; - } - } - this.commandAlreadySent = (BlockingQueue) SystemUtils - .createTransferQueue(); - this.commandFactory = commandFactory; - } - - public InetSocketAddressWrapper getInetSocketAddressWrapper() { - return this.inetSocketAddressWrapper; - } - - public int getOrder() { - return this.getInetSocketAddressWrapper().getOrder(); - } - - public int getWeight() { - return this.getInetSocketAddressWrapper().getWeight(); - } - - public void setInetSocketAddressWrapper( - InetSocketAddressWrapper inetSocketAddressWrapper) { - this.inetSocketAddressWrapper = inetSocketAddressWrapper; - } - - @Override - public String toString() { - return SystemUtils.getRawAddress(this.getRemoteSocketAddress()) + ":" - + this.getRemoteSocketAddress().getPort(); - } - - public void destroy() { - Command command = this.currentCommand.get(); - if (command != null) { - command.setException( - new MemcachedException("Session has been closed")); - CountDownLatch latch = command.getLatch(); - if (latch != null) { - latch.countDown(); - } - } - while ((command = this.commandAlreadySent.poll()) != null) { - command.setException( - new MemcachedException("Session has been closed")); - CountDownLatch latch = command.getLatch(); - if (latch != null) { - latch.countDown(); - } - } - - } - - @Override - public InetSocketAddress getRemoteSocketAddress() { - InetSocketAddress result = super.getRemoteSocketAddress(); - if (result == null && this.remoteSocketAddress != null) { - result = (InetSocketAddress) this.remoteSocketAddress; - } - return result; - } - - @Override - protected WriteMessage preprocessWriteMessage(WriteMessage writeMessage) { - Command currentCommand = (Command) writeMessage; - // Check if IoBuffer is null - if (currentCommand.getIoBuffer() == null) { - currentCommand.encode(); - } - if (currentCommand.getStatus() == OperationStatus.SENDING) { - /** - * optimize commands - */ - currentCommand = this.optimiezer.optimize(currentCommand, - this.writeQueue, this.commandAlreadySent, - this.sendBufferSize); - } - - currentCommand.setStatus(OperationStatus.WRITING); - if (!currentCommand.isAdded() && (!currentCommand.isNoreply() - || this.commandFactory.getProtocol() == Protocol.Binary)) { - currentCommand.setAdded(true); - this.addCommand(currentCommand); - } - - return currentCommand; - } - - public boolean isAuthFailed() { - return this.authFailed; - } - - public void setAuthFailed(boolean authFailed) { - this.authFailed = authFailed; - } - - private BufferAllocator bufferAllocator; - - public final BufferAllocator getBufferAllocator() { - return this.bufferAllocator; - } - - public final void setBufferAllocator(BufferAllocator bufferAllocator) { - this.bufferAllocator = bufferAllocator; - } - - @Override - protected final WriteMessage wrapMessage(Object msg, - Future writeFuture) { - ((Command) msg).encode(); - ((Command) msg).setWriteFuture((FutureImpl) writeFuture); - if (log.isDebugEnabled()) { - log.debug("After encoding" + ((Command) msg).toString()); - } - return (WriteMessage) msg; - } - - /** - * get current command from queue - * - * @return - */ - private Command takeExecutingCommand() { - try { - return this.commandAlreadySent.take(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - return null; - } - - /** - * is allow auto recconect if closed? - * - * @return - */ - public boolean isAllowReconnect() { - return this.allowReconnect; - } - - public void setAllowReconnect(boolean reconnected) { - this.allowReconnect = reconnected; - } - - public void addCommand(Command command) { - this.commandAlreadySent.add(command); - } - - public void setCurrentCommand(Command cmd) { - this.currentCommand.set(cmd); - } - - public Command getCurrentCommand() { - return this.currentCommand.get(); - } - - public void takeCurrentCommand() { - this.setCurrentCommand(this.takeExecutingCommand()); - } - - public void quit() { - this.write(this.commandFactory.createQuitCommand()); - } -} +/** + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.impl; + +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.SocketException; +import java.nio.channels.SocketChannel; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicReference; +import net.rubyeye.xmemcached.CommandFactory; +import net.rubyeye.xmemcached.MemcachedOptimizer; +import net.rubyeye.xmemcached.buffer.BufferAllocator; +import net.rubyeye.xmemcached.command.Command; +import net.rubyeye.xmemcached.command.OperationStatus; +import net.rubyeye.xmemcached.exception.MemcachedException; +import net.rubyeye.xmemcached.networking.MemcachedSession; +import net.rubyeye.xmemcached.utils.InetSocketAddressWrapper; +import net.rubyeye.xmemcached.utils.Protocol; +import com.google.code.yanf4j.core.WriteMessage; +import com.google.code.yanf4j.core.impl.FutureImpl; +import com.google.code.yanf4j.nio.NioSessionConfig; +import com.google.code.yanf4j.nio.impl.NioTCPSession; +import com.google.code.yanf4j.util.LinkedTransferQueue; +import com.google.code.yanf4j.util.SystemUtils; + +/** + * Connected session for a memcached server + * + * @author dennis + */ +public class MemcachedTCPSession extends NioTCPSession implements MemcachedSession { + + /** + * Command which are already sent + */ + protected BlockingQueue commandAlreadySent; + + private final AtomicReference currentCommand = + new LinkedTransferQueue.PaddedAtomicReference(null); + + private SocketAddress remoteSocketAddress; // prevent channel is closed + private int sendBufferSize; + private final MemcachedOptimizer optimiezer; + private boolean allowReconnect; + + private volatile boolean authFailed; + + private final CommandFactory commandFactory; + + private InetSocketAddressWrapper inetSocketAddressWrapper; + + public MemcachedTCPSession(NioSessionConfig sessionConfig, int readRecvBufferSize, + MemcachedOptimizer optimiezer, int readThreadCount, CommandFactory commandFactory) { + super(sessionConfig, readRecvBufferSize); + this.optimiezer = optimiezer; + if (this.selectableChannel != null) { + this.remoteSocketAddress = + ((SocketChannel) this.selectableChannel).socket().getRemoteSocketAddress(); + this.allowReconnect = true; + try { + this.sendBufferSize = ((SocketChannel) this.selectableChannel).socket().getSendBufferSize(); + } catch (SocketException e) { + this.sendBufferSize = 8 * 1024; + } + } + this.commandAlreadySent = (BlockingQueue) SystemUtils.createTransferQueue(); + this.commandFactory = commandFactory; + } + + public InetSocketAddressWrapper getInetSocketAddressWrapper() { + return this.inetSocketAddressWrapper; + } + + public int getOrder() { + return this.getInetSocketAddressWrapper().getOrder(); + } + + public int getWeight() { + return this.getInetSocketAddressWrapper().getWeight(); + } + + public void setInetSocketAddressWrapper(InetSocketAddressWrapper inetSocketAddressWrapper) { + this.inetSocketAddressWrapper = inetSocketAddressWrapper; + } + + @Override + public String toString() { + return SystemUtils.getRawAddress(this.getRemoteSocketAddress()) + ":" + + this.getRemoteSocketAddress().getPort(); + } + + public void destroy() { + Command command = this.currentCommand.get(); + if (command != null) { + command.setException(new MemcachedException("Session has been closed")); + CountDownLatch latch = command.getLatch(); + if (latch != null) { + latch.countDown(); + } + } + while ((command = this.commandAlreadySent.poll()) != null) { + command.setException(new MemcachedException("Session has been closed")); + CountDownLatch latch = command.getLatch(); + if (latch != null) { + latch.countDown(); + } + } + + } + + @Override + public InetSocketAddress getRemoteSocketAddress() { + InetSocketAddress result = super.getRemoteSocketAddress(); + if (result == null && this.remoteSocketAddress != null) { + result = (InetSocketAddress) this.remoteSocketAddress; + } + return result; + } + + @Override + protected WriteMessage preprocessWriteMessage(WriteMessage writeMessage) { + Command currentCommand = (Command) writeMessage; + // Check if IoBuffer is null + if (currentCommand.getIoBuffer() == null) { + currentCommand.encode(); + } + if (currentCommand.getStatus() == OperationStatus.SENDING) { + /** + * optimize commands + */ + currentCommand = this.optimiezer.optimize(currentCommand, this.writeQueue, + this.commandAlreadySent, this.sendBufferSize); + } + + currentCommand.setStatus(OperationStatus.WRITING); + if (!currentCommand.isAdded() + && (!currentCommand.isNoreply() || this.commandFactory.getProtocol() == Protocol.Binary)) { + currentCommand.setAdded(true); + this.addCommand(currentCommand); + } + + return currentCommand; + } + + public boolean isAuthFailed() { + return this.authFailed; + } + + public void setAuthFailed(boolean authFailed) { + this.authFailed = authFailed; + } + + private BufferAllocator bufferAllocator; + + public final BufferAllocator getBufferAllocator() { + return this.bufferAllocator; + } + + public final void setBufferAllocator(BufferAllocator bufferAllocator) { + this.bufferAllocator = bufferAllocator; + } + + @Override + protected final WriteMessage wrapMessage(Object msg, Future writeFuture) { + ((Command) msg).encode(); + ((Command) msg).setWriteFuture((FutureImpl) writeFuture); + if (log.isDebugEnabled()) { + log.debug("After encoding" + ((Command) msg).toString()); + } + return (WriteMessage) msg; + } + + /** + * get current command from queue + * + * @return + */ + private Command takeExecutingCommand() { + try { + return this.commandAlreadySent.take(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + return null; + } + + /** + * is allow auto recconect if closed? + * + * @return + */ + public boolean isAllowReconnect() { + return this.allowReconnect; + } + + public void setAllowReconnect(boolean reconnected) { + this.allowReconnect = reconnected; + } + + public void addCommand(Command command) { + this.commandAlreadySent.add(command); + } + + public void setCurrentCommand(Command cmd) { + this.currentCommand.set(cmd); + } + + public Command getCurrentCommand() { + return this.currentCommand.get(); + } + + public void takeCurrentCommand() { + this.setCurrentCommand(this.takeExecutingCommand()); + } + + public void quit() { + this.write(this.commandFactory.createQuitCommand()); + } +} diff --git a/src/main/java/net/rubyeye/xmemcached/impl/Optimizer.java b/src/main/java/net/rubyeye/xmemcached/impl/Optimizer.java index 0bafb988d..afbadb482 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/Optimizer.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/Optimizer.java @@ -1,653 +1,607 @@ -/** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 - */ -/** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 net.rubyeye.xmemcached.impl; - -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Queue; -import java.util.concurrent.CountDownLatch; - -import net.rubyeye.xmemcached.MemcachedOptimizer; -import net.rubyeye.xmemcached.buffer.BufferAllocator; -import net.rubyeye.xmemcached.command.AssocCommandAware; -import net.rubyeye.xmemcached.command.Command; -import net.rubyeye.xmemcached.command.CommandType; -import net.rubyeye.xmemcached.command.OperationStatus; -import net.rubyeye.xmemcached.command.binary.BaseBinaryCommand; -import net.rubyeye.xmemcached.command.binary.BinaryGetCommand; -import net.rubyeye.xmemcached.command.binary.BinaryGetMultiCommand; -import net.rubyeye.xmemcached.command.binary.BinarySetMultiCommand; -import net.rubyeye.xmemcached.command.binary.BinaryStoreCommand; -import net.rubyeye.xmemcached.command.binary.OpCode; -import net.rubyeye.xmemcached.command.text.TextGetOneCommand; -import net.rubyeye.xmemcached.monitor.Constants; -import net.rubyeye.xmemcached.monitor.MemcachedClientNameHolder; -import net.rubyeye.xmemcached.monitor.XMemcachedMbeanServer; -import net.rubyeye.xmemcached.utils.ByteUtils; -import net.rubyeye.xmemcached.utils.OpaqueGenerater; -import net.rubyeye.xmemcached.utils.Protocol; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.code.yanf4j.buffer.IoBuffer; -import com.google.code.yanf4j.core.impl.FutureImpl; - -/** - * Memcached command optimizer,merge single-get comands to multi-get - * command,merge ByteBuffers to fit the socket's sendBufferSize etc. - * - * @author dennis - */ -public class Optimizer implements OptimizerMBean, MemcachedOptimizer { - - public static final int DEFAULT_MERGE_FACTOR = 50; - private int mergeFactor = DEFAULT_MERGE_FACTOR; // default merge factor; - private boolean optimiezeGet = true; - private final boolean optimiezeSet = true; - private boolean optimiezeMergeBuffer = true; - private static final Logger log = LoggerFactory.getLogger(Optimizer.class); - private Protocol protocol = Protocol.Binary; - - public Optimizer(Protocol protocol) { - XMemcachedMbeanServer.getInstance().registMBean(this, - this.getClass().getPackage().getName() + ":type=" - + this.getClass().getSimpleName() + "-" - + MemcachedClientNameHolder.getName()); - this.protocol = protocol; - } - - public void setBufferAllocator(BufferAllocator bufferAllocator) { - - } - - public int getMergeFactor() { - return this.mergeFactor; - } - - public void setMergeFactor(int mergeFactor) { - if (this.mergeFactor != mergeFactor) { - log.warn("change mergeFactor from " + this.mergeFactor + " to " - + mergeFactor); - } - this.mergeFactor = mergeFactor; - - } - - public boolean isOptimizeGet() { - return this.optimiezeGet; - } - - public void setOptimizeGet(boolean optimiezeGet) { - log.warn(optimiezeGet - ? "Enable merge get commands" - : "Disable merge get commands"); - this.optimiezeGet = optimiezeGet; - } - - public boolean isOptimizeMergeBuffer() { - return this.optimiezeMergeBuffer; - } - - public void setOptimizeMergeBuffer(boolean optimiezeMergeBuffer) { - log.warn(optimiezeMergeBuffer - ? "Enable merge buffers" - : "Disable merge buffers"); - this.optimiezeMergeBuffer = optimiezeMergeBuffer; - } - - @SuppressWarnings("unchecked") - public Command optimize(final Command currentCommand, - final Queue writeQueue, final Queue executingCmds, - int sendBufferSize) { - Command optimiezeCommand = currentCommand; - optimiezeCommand = this.optimiezeGet(writeQueue, executingCmds, - optimiezeCommand); - optimiezeCommand = this.optimiezeSet(writeQueue, executingCmds, - optimiezeCommand, sendBufferSize); - optimiezeCommand = this.optimiezeMergeBuffer(optimiezeCommand, - writeQueue, executingCmds, sendBufferSize); - return optimiezeCommand; - } - - /** - * merge buffers to fit socket's send buffer size - * - * @param currentCommand - * @return - * @throws InterruptedException - */ - @SuppressWarnings("unchecked") - public final Command optimiezeMergeBuffer(Command optimiezeCommand, - final Queue writeQueue, final Queue executingCmds, - int sendBufferSize) { - if (log.isDebugEnabled()) { - log.debug("Optimieze merge buffer:" + optimiezeCommand.toString()); - } - if (this.optimiezeMergeBuffer && optimiezeCommand.getIoBuffer() - .remaining() < sendBufferSize - 24) { - optimiezeCommand = this.mergeBuffer(optimiezeCommand, writeQueue, - executingCmds, sendBufferSize); - } - return optimiezeCommand; - } - - /** - * Merge get operation to multi-get operation - * - * @param currentCmd - * @param mergeCommands - * @return - * @throws InterruptedException - */ - @SuppressWarnings("unchecked") - public final Command optimiezeGet(final Queue writeQueue, - final Queue executingCmds, Command optimiezeCommand) { - if (optimiezeCommand.getCommandType() == CommandType.GET_ONE - || optimiezeCommand.getCommandType() == CommandType.GETS_ONE) { - if (this.optimiezeGet) { - optimiezeCommand = this.mergeGetCommands(optimiezeCommand, - writeQueue, executingCmds, - optimiezeCommand.getCommandType()); - } - } - return optimiezeCommand; - } - - public final Command optimiezeSet(final Queue writeQueue, - final Queue executingCmds, Command optimiezeCommand, - int sendBufferSize) { - if (this.optimiezeSet - && optimiezeCommand.getCommandType() == CommandType.SET - && !optimiezeCommand.isNoreply() - && this.protocol == Protocol.Binary) { - optimiezeCommand = this.mergeSetCommands(optimiezeCommand, - writeQueue, executingCmds, - optimiezeCommand.getCommandType(), sendBufferSize); - } - return optimiezeCommand; - } - - @SuppressWarnings("unchecked") - private final Command mergeBuffer(final Command firstCommand, - final Queue writeQueue, final Queue executingCmds, - final int sendBufferSize) { - Command lastCommand = firstCommand; - Command nextCmd = (Command) writeQueue.peek(); - if (nextCmd == null) { - return lastCommand; - } - - final List commands = this.getLocalList(); - final ByteBuffer firstBuffer = firstCommand.getIoBuffer().buf(); - int totalBytes = firstBuffer.remaining(); - commands.add(firstCommand); - boolean wasFirst = true; - while (totalBytes + nextCmd.getIoBuffer().remaining() <= sendBufferSize - && (nextCmd = (Command) writeQueue.peek()) != null) { - if (nextCmd.getStatus() == OperationStatus.WRITING) { - break; - } - if (nextCmd.isCancel()) { - writeQueue.remove(); - continue; - } - nextCmd.setStatus(OperationStatus.WRITING); - - writeQueue.remove(); - - if (wasFirst) { - wasFirst = false; - } - // if it is get_one command,try to merge get commands - if ((nextCmd.getCommandType() == CommandType.GET_ONE - || nextCmd.getCommandType() == CommandType.GETS_ONE) - && this.optimiezeGet) { - nextCmd = this.mergeGetCommands(nextCmd, writeQueue, - executingCmds, nextCmd.getCommandType()); - } - - commands.add(nextCmd); - lastCommand = nextCmd; - totalBytes += nextCmd.getIoBuffer().remaining(); - if (totalBytes > sendBufferSize) { - break; - } - - } - if (commands.size() > 1) { - byte[] buf = new byte[totalBytes]; - int offset = 0; - for (Command command : commands) { - byte[] ba = command.getIoBuffer().array(); - System.arraycopy(ba, 0, buf, offset, ba.length); - offset += ba.length; - if (command != lastCommand && (!command.isNoreply() - || command instanceof BaseBinaryCommand)) { - executingCmds.add(command); - } - } - lastCommand.setIoBuffer(IoBuffer.wrap(buf)); - } - return lastCommand; - } - - private final ThreadLocal> threadLocal = new ThreadLocal>() { - - @Override - protected List initialValue() { - return new ArrayList(Optimizer.this.mergeFactor); - } - }; - - public final List getLocalList() { - List list = this.threadLocal.get(); - list.clear(); - return list; - } - - static interface CommandCollector { - public Object getResult(); - - public void visit(Command command); - - public void finish(); - - public CommandCollector reset(); - } - - static class KeyStringCollector implements CommandCollector { - char[] buf = new char[1024 * 2]; - int count = 0; - boolean wasFirst = true; - - public CommandCollector reset() { - this.count = 0; - this.wasFirst = true; - return this; - } - - public Object getResult() { - return new String(this.buf, 0, this.count); - } - - public void visit(Command command) { - if (this.wasFirst) { - this.append(command.getKey()); - this.wasFirst = false; - } else { - this.append(" "); - this.append(command.getKey()); - } - } - - private void expandCapacity(int minimumCapacity) { - int newCapacity = (this.buf.length + 1) * 2; - if (newCapacity < 0) { - newCapacity = Integer.MAX_VALUE; - } else if (minimumCapacity > newCapacity) { - newCapacity = minimumCapacity; - } - char[] copy = new char[newCapacity]; - System.arraycopy(this.buf, 0, copy, 0, - Math.min(this.buf.length, newCapacity)); - this.buf = copy; - } - - private void append(String str) { - int len = str.length(); - if (len == 0) { - return; - } - int newCount = this.count + len; - if (newCount > this.buf.length) { - this.expandCapacity(newCount); - } - str.getChars(0, len, this.buf, this.count); - this.count = newCount; - } - - public void finish() { - // do nothing - - } - - } - - private static class BinarySetQCollector implements CommandCollector { - ArrayList bufferList = new ArrayList(); - int totalBytes; - BinaryStoreCommand prevCommand; - Map mergeCommands; - - public CommandCollector reset() { - this.bufferList.clear(); - this.totalBytes = 0; - this.prevCommand = null; - this.mergeCommands = null; - return this; - } - - public Object getResult() { - byte[] buf = new byte[this.totalBytes]; - int offset = 0; - for (IoBuffer buffer : this.bufferList) { - byte[] ba = buffer.array(); - System.arraycopy(ba, 0, buf, offset, ba.length); - offset += ba.length; - } - BinarySetMultiCommand resultCommand = new BinarySetMultiCommand( - null, CommandType.SET_MANY, new CountDownLatch(1)); - resultCommand.setIoBuffer(IoBuffer.wrap(buf)); - resultCommand.setMergeCommands(this.mergeCommands); - resultCommand.setMergeCount(this.mergeCommands.size()); - return resultCommand; - } - - public void visit(Command command) { - - // Encode prev command - if (this.prevCommand != null) { - // first n-1 send setq command - BinaryStoreCommand setqCmd = new BinaryStoreCommand( - this.prevCommand.getKey(), - this.prevCommand.getKeyBytes(), CommandType.SET, null, - this.prevCommand.getExpTime(), - this.prevCommand.getCas(), - // set noreply to be true - this.prevCommand.getValue(), true, - this.prevCommand.getTranscoder()); - // We must set the opaque to get error message. - int opaque = OpaqueGenerater.getInstance().getNextValue(); - setqCmd.setOpaque(opaque); - setqCmd.encode(); - this.totalBytes += setqCmd.getIoBuffer().remaining(); - - this.bufferList.add(setqCmd.getIoBuffer()); - // GC friendly - setqCmd.setIoBuffer(MemcachedHandler.EMPTY_BUF); - setqCmd.setValue(null); - this.prevCommand.setValue(null); - this.prevCommand.setIoBuffer(MemcachedHandler.EMPTY_BUF); - if (this.mergeCommands == null) { - this.mergeCommands = new HashMap(); - } - this.mergeCommands.put(opaque, this.prevCommand); - } - this.prevCommand = (BinaryStoreCommand) command; - } - - public void finish() { - if (this.mergeCommands == null) { - return; - } - // prevCommand is the last command,last command must be a SET - // command,ensure - // previous SETQ commands sending response back - BinaryStoreCommand setqCmd = new BinaryStoreCommand( - this.prevCommand.getKey(), this.prevCommand.getKeyBytes(), - CommandType.SET, null, this.prevCommand.getExpTime(), - this.prevCommand.getCas(), - // set noreply to be false. - this.prevCommand.getValue(), false, - this.prevCommand.getTranscoder()); - // We must set the opaque to get error message. - int opaque = OpaqueGenerater.getInstance().getNextValue(); - setqCmd.setOpaque(opaque); - setqCmd.encode(); - this.bufferList.add(setqCmd.getIoBuffer()); - this.totalBytes += setqCmd.getIoBuffer().remaining(); - if (this.mergeCommands != null) { - this.mergeCommands.put(opaque, this.prevCommand); - } - } - - } - - private static class BinaryGetQCollector implements CommandCollector { - ArrayList bufferList = new ArrayList(50); - int totalBytes; - Command prevCommand; - - public CommandCollector reset() { - this.bufferList.clear(); - this.totalBytes = 0; - this.prevCommand = null; - return this; - } - - public Object getResult() { - byte[] buf = new byte[this.totalBytes]; - int offset = 0; - for (IoBuffer buffer : this.bufferList) { - byte[] ba = buffer.array(); - System.arraycopy(ba, 0, buf, offset, ba.length); - offset += ba.length; - } - BinaryGetMultiCommand resultCommand = new BinaryGetMultiCommand( - null, CommandType.GET_MANY, new CountDownLatch(1)); - resultCommand.setIoBuffer(IoBuffer.wrap(buf)); - return resultCommand; - } - - public void visit(Command command) { - // Encode prev command - if (this.prevCommand != null) { - // first n-1 send getq command - Command getqCommand = new BinaryGetCommand( - this.prevCommand.getKey(), - this.prevCommand.getKeyBytes(), null, null, - OpCode.GET_KEY_QUIETLY, true); - getqCommand.encode(); - this.totalBytes += getqCommand.getIoBuffer().remaining(); - this.bufferList.add(getqCommand.getIoBuffer()); - } - this.prevCommand = command; - } - - public void finish() { - // prev command is the last command,last command must be getk,ensure - // getq commands sending response back - Command lastGetKCommand = new BinaryGetCommand( - this.prevCommand.getKey(), this.prevCommand.getKeyBytes(), - CommandType.GET_ONE, new CountDownLatch(1), OpCode.GET_KEY, - false); - lastGetKCommand.encode(); - this.bufferList.add(lastGetKCommand.getIoBuffer()); - this.totalBytes += lastGetKCommand.getIoBuffer().remaining(); - } - - } - - @SuppressWarnings("unchecked") - private final Command mergeGetCommands(final Command currentCmd, - final Queue writeQueue, final Queue executingCmds, - CommandType expectedCommandType) { - Map mergeCommands = null; - int mergeCount = 1; - final CommandCollector commandCollector = this - .createGetCommandCollector(); - currentCmd.setStatus(OperationStatus.WRITING); - - commandCollector.visit(currentCmd); - while (mergeCount < this.mergeFactor) { - Command nextCmd = (Command) writeQueue.peek(); - if (nextCmd == null) { - break; - } - if (nextCmd.isCancel()) { - writeQueue.remove(); - continue; - } - if (nextCmd.getCommandType() == expectedCommandType) { - if (mergeCommands == null) { // lazy initialize - mergeCommands = new HashMap( - this.mergeFactor / 2); - mergeCommands.put(currentCmd.getKey(), currentCmd); - } - if (log.isDebugEnabled()) { - log.debug("Merge get command:" + nextCmd.toString()); - } - nextCmd.setStatus(OperationStatus.WRITING); - Command removedCommand = (Command) writeQueue.remove(); - // If the key is exists,add the command to associated list. - if (mergeCommands.containsKey(removedCommand.getKey())) { - final AssocCommandAware mergedGetCommand = (AssocCommandAware) mergeCommands - .get(removedCommand.getKey()); - if (mergedGetCommand.getAssocCommands() == null) { - mergedGetCommand - .setAssocCommands(new ArrayList(5)); - } - mergedGetCommand.getAssocCommands().add(removedCommand); - } else { - commandCollector.visit(nextCmd); - mergeCommands.put(removedCommand.getKey(), removedCommand); - } - mergeCount++; - } else { - break; - } - } - if (mergeCount == 1) { - return currentCmd; - } else { - commandCollector.finish(); - if (log.isDebugEnabled()) { - log.debug("Merge optimieze:merge " + mergeCount - + " get commands"); - } - return this.newMergedCommand(mergeCommands, mergeCount, - commandCollector, expectedCommandType); - } - } - - private static final ThreadLocal BIN_SET_CMD_COLLECTOR_THREAD_LOCAL = new ThreadLocal() { - - @Override - protected BinarySetQCollector initialValue() { - return new BinarySetQCollector(); - } - - }; - - private final Command mergeSetCommands(final Command currentCmd, - final Queue writeQueue, final Queue executingCmds, - CommandType expectedCommandType, int sendBufferSize) { - int mergeCount = 1; - final CommandCollector commandCollector = BIN_SET_CMD_COLLECTOR_THREAD_LOCAL - .get().reset(); - currentCmd.setStatus(OperationStatus.WRITING); - int totalBytes = currentCmd.getIoBuffer().remaining(); - commandCollector.visit(currentCmd); - while (mergeCount < this.mergeFactor && totalBytes <= sendBufferSize) { - Command nextCmd = (Command) writeQueue.peek(); - if (nextCmd == null) { - break; - } - if (nextCmd.isCancel()) { - writeQueue.remove(); - continue; - } - if (nextCmd.getCommandType() == expectedCommandType - && !nextCmd.isNoreply()) { - if (log.isDebugEnabled()) { - log.debug("Merge set command:" + nextCmd.toString()); - } - nextCmd.setStatus(OperationStatus.WRITING); - writeQueue.remove(); - - commandCollector.visit(nextCmd); - - mergeCount++; - } else { - break; - } - totalBytes += nextCmd.getIoBuffer().remaining(); - } - if (mergeCount == 1) { - return currentCmd; - } else { - commandCollector.finish(); - if (log.isDebugEnabled()) { - log.debug("Merge optimieze:merge " + mergeCount - + " get commands"); - } - return (Command) commandCollector.getResult(); - } - } - - private static ThreadLocal TEXT_GET_CMD_COLLECTOR_THREAD_LOCAL = new ThreadLocal() { - @Override - public KeyStringCollector initialValue() { - return new KeyStringCollector(); - } - }; - - private static ThreadLocal BIN_GET_CMD_COLLECTOR_THREAD_LOCAL = new ThreadLocal() { - @Override - public BinaryGetQCollector initialValue() { - return new BinaryGetQCollector(); - } - }; - - private CommandCollector createGetCommandCollector() { - switch (this.protocol) { - case Binary : - return BIN_GET_CMD_COLLECTOR_THREAD_LOCAL.get().reset(); - default : - return TEXT_GET_CMD_COLLECTOR_THREAD_LOCAL.get().reset(); - } - } - - private Command newMergedCommand(final Map mergeCommands, - int mergeCount, final CommandCollector commandCollector, - final CommandType commandType) { - if (this.protocol == Protocol.Text) { - String resultKey = (String) commandCollector.getResult(); - - byte[] keyBytes = ByteUtils.getBytes(resultKey); - byte[] cmdBytes = commandType == CommandType.GET_ONE - ? Constants.GET - : Constants.GETS; - final byte[] buf = new byte[cmdBytes.length + 3 + keyBytes.length]; - ByteUtils.setArguments(buf, 0, cmdBytes, keyBytes); - TextGetOneCommand cmd = new TextGetOneCommand(resultKey, keyBytes, - commandType, null); - cmd.setMergeCommands(mergeCommands); - cmd.setWriteFuture(new FutureImpl()); - cmd.setMergeCount(mergeCount); - cmd.setIoBuffer(IoBuffer.wrap(buf)); - return cmd; - } else { - BinaryGetMultiCommand result = (BinaryGetMultiCommand) commandCollector - .getResult(); - result.setMergeCount(mergeCount); - result.setMergeCommands(mergeCommands); - return result; - } - } -} +/** + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 + */ +/** + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.impl; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.concurrent.CountDownLatch; +import net.rubyeye.xmemcached.MemcachedOptimizer; +import net.rubyeye.xmemcached.buffer.BufferAllocator; +import net.rubyeye.xmemcached.command.AssocCommandAware; +import net.rubyeye.xmemcached.command.Command; +import net.rubyeye.xmemcached.command.CommandType; +import net.rubyeye.xmemcached.command.OperationStatus; +import net.rubyeye.xmemcached.command.binary.BaseBinaryCommand; +import net.rubyeye.xmemcached.command.binary.BinaryGetCommand; +import net.rubyeye.xmemcached.command.binary.BinaryGetMultiCommand; +import net.rubyeye.xmemcached.command.binary.BinarySetMultiCommand; +import net.rubyeye.xmemcached.command.binary.BinaryStoreCommand; +import net.rubyeye.xmemcached.command.binary.OpCode; +import net.rubyeye.xmemcached.command.text.TextGetOneCommand; +import net.rubyeye.xmemcached.monitor.Constants; +import net.rubyeye.xmemcached.monitor.MemcachedClientNameHolder; +import net.rubyeye.xmemcached.monitor.XMemcachedMbeanServer; +import net.rubyeye.xmemcached.utils.ByteUtils; +import net.rubyeye.xmemcached.utils.OpaqueGenerater; +import net.rubyeye.xmemcached.utils.Protocol; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.google.code.yanf4j.buffer.IoBuffer; +import com.google.code.yanf4j.core.impl.FutureImpl; + +/** + * Memcached command optimizer,merge single-get comands to multi-get command,merge ByteBuffers to + * fit the socket's sendBufferSize etc. + * + * @author dennis + */ +public class Optimizer implements OptimizerMBean, MemcachedOptimizer { + + public static final int DEFAULT_MERGE_FACTOR = 50; + private int mergeFactor = DEFAULT_MERGE_FACTOR; // default merge factor; + private boolean optimiezeGet = true; + private final boolean optimiezeSet = true; + private boolean optimiezeMergeBuffer = true; + private static final Logger log = LoggerFactory.getLogger(Optimizer.class); + private Protocol protocol = Protocol.Binary; + + public Optimizer(Protocol protocol) { + XMemcachedMbeanServer.getInstance().registMBean(this, this.getClass().getPackage().getName() + + ":type=" + this.getClass().getSimpleName() + "-" + MemcachedClientNameHolder.getName()); + this.protocol = protocol; + } + + public void setBufferAllocator(BufferAllocator bufferAllocator) { + + } + + public int getMergeFactor() { + return this.mergeFactor; + } + + public void setMergeFactor(int mergeFactor) { + if (this.mergeFactor != mergeFactor) { + log.warn("change mergeFactor from " + this.mergeFactor + " to " + mergeFactor); + } + this.mergeFactor = mergeFactor; + + } + + public boolean isOptimizeGet() { + return this.optimiezeGet; + } + + public void setOptimizeGet(boolean optimiezeGet) { + log.warn(optimiezeGet ? "Enable merge get commands" : "Disable merge get commands"); + this.optimiezeGet = optimiezeGet; + } + + public boolean isOptimizeMergeBuffer() { + return this.optimiezeMergeBuffer; + } + + public void setOptimizeMergeBuffer(boolean optimiezeMergeBuffer) { + log.warn(optimiezeMergeBuffer ? "Enable merge buffers" : "Disable merge buffers"); + this.optimiezeMergeBuffer = optimiezeMergeBuffer; + } + + @SuppressWarnings("unchecked") + public Command optimize(final Command currentCommand, final Queue writeQueue, + final Queue executingCmds, int sendBufferSize) { + Command optimiezeCommand = currentCommand; + optimiezeCommand = this.optimiezeGet(writeQueue, executingCmds, optimiezeCommand); + optimiezeCommand = + this.optimiezeSet(writeQueue, executingCmds, optimiezeCommand, sendBufferSize); + optimiezeCommand = + this.optimiezeMergeBuffer(optimiezeCommand, writeQueue, executingCmds, sendBufferSize); + return optimiezeCommand; + } + + /** + * merge buffers to fit socket's send buffer size + * + * @param currentCommand + * @return + * @throws InterruptedException + */ + @SuppressWarnings("unchecked") + public final Command optimiezeMergeBuffer(Command optimiezeCommand, final Queue writeQueue, + final Queue executingCmds, int sendBufferSize) { + if (log.isDebugEnabled()) { + log.debug("Optimieze merge buffer:" + optimiezeCommand.toString()); + } + if (this.optimiezeMergeBuffer + && optimiezeCommand.getIoBuffer().remaining() < sendBufferSize - 24) { + optimiezeCommand = + this.mergeBuffer(optimiezeCommand, writeQueue, executingCmds, sendBufferSize); + } + return optimiezeCommand; + } + + /** + * Merge get operation to multi-get operation + * + * @param currentCmd + * @param mergeCommands + * @return + * @throws InterruptedException + */ + @SuppressWarnings("unchecked") + public final Command optimiezeGet(final Queue writeQueue, final Queue executingCmds, + Command optimiezeCommand) { + if (optimiezeCommand.getCommandType() == CommandType.GET_ONE + || optimiezeCommand.getCommandType() == CommandType.GETS_ONE) { + if (this.optimiezeGet) { + optimiezeCommand = this.mergeGetCommands(optimiezeCommand, writeQueue, executingCmds, + optimiezeCommand.getCommandType()); + } + } + return optimiezeCommand; + } + + public final Command optimiezeSet(final Queue writeQueue, final Queue executingCmds, + Command optimiezeCommand, int sendBufferSize) { + if (this.optimiezeSet && optimiezeCommand.getCommandType() == CommandType.SET + && !optimiezeCommand.isNoreply() && this.protocol == Protocol.Binary) { + optimiezeCommand = this.mergeSetCommands(optimiezeCommand, writeQueue, executingCmds, + optimiezeCommand.getCommandType(), sendBufferSize); + } + return optimiezeCommand; + } + + @SuppressWarnings("unchecked") + private final Command mergeBuffer(final Command firstCommand, final Queue writeQueue, + final Queue executingCmds, final int sendBufferSize) { + Command lastCommand = firstCommand; + Command nextCmd = (Command) writeQueue.peek(); + if (nextCmd == null) { + return lastCommand; + } + + final List commands = this.getLocalList(); + final ByteBuffer firstBuffer = firstCommand.getIoBuffer().buf(); + int totalBytes = firstBuffer.remaining(); + commands.add(firstCommand); + boolean wasFirst = true; + while (totalBytes + nextCmd.getIoBuffer().remaining() <= sendBufferSize + && (nextCmd = (Command) writeQueue.peek()) != null) { + if (nextCmd.getStatus() == OperationStatus.WRITING) { + break; + } + if (nextCmd.isCancel()) { + writeQueue.remove(); + continue; + } + nextCmd.setStatus(OperationStatus.WRITING); + + writeQueue.remove(); + + if (wasFirst) { + wasFirst = false; + } + // if it is get_one command,try to merge get commands + if ((nextCmd.getCommandType() == CommandType.GET_ONE + || nextCmd.getCommandType() == CommandType.GETS_ONE) && this.optimiezeGet) { + nextCmd = + this.mergeGetCommands(nextCmd, writeQueue, executingCmds, nextCmd.getCommandType()); + } + + commands.add(nextCmd); + lastCommand = nextCmd; + totalBytes += nextCmd.getIoBuffer().remaining(); + if (totalBytes > sendBufferSize) { + break; + } + + } + if (commands.size() > 1) { + byte[] buf = new byte[totalBytes]; + int offset = 0; + for (Command command : commands) { + byte[] ba = command.getIoBuffer().array(); + System.arraycopy(ba, 0, buf, offset, ba.length); + offset += ba.length; + if (command != lastCommand + && (!command.isNoreply() || command instanceof BaseBinaryCommand)) { + executingCmds.add(command); + } + } + lastCommand.setIoBuffer(IoBuffer.wrap(buf)); + } + return lastCommand; + } + + private final ThreadLocal> threadLocal = new ThreadLocal>() { + + @Override + protected List initialValue() { + return new ArrayList(Optimizer.this.mergeFactor); + } + }; + + public final List getLocalList() { + List list = this.threadLocal.get(); + list.clear(); + return list; + } + + static interface CommandCollector { + public Object getResult(); + + public void visit(Command command); + + public void finish(); + + public CommandCollector reset(); + } + + static class KeyStringCollector implements CommandCollector { + char[] buf = new char[1024 * 2]; + int count = 0; + boolean wasFirst = true; + + public CommandCollector reset() { + this.count = 0; + this.wasFirst = true; + return this; + } + + public Object getResult() { + return new String(this.buf, 0, this.count); + } + + public void visit(Command command) { + if (this.wasFirst) { + this.append(command.getKey()); + this.wasFirst = false; + } else { + this.append(" "); + this.append(command.getKey()); + } + } + + private void expandCapacity(int minimumCapacity) { + int newCapacity = (this.buf.length + 1) * 2; + if (newCapacity < 0) { + newCapacity = Integer.MAX_VALUE; + } else if (minimumCapacity > newCapacity) { + newCapacity = minimumCapacity; + } + char[] copy = new char[newCapacity]; + System.arraycopy(this.buf, 0, copy, 0, Math.min(this.buf.length, newCapacity)); + this.buf = copy; + } + + private void append(String str) { + int len = str.length(); + if (len == 0) { + return; + } + int newCount = this.count + len; + if (newCount > this.buf.length) { + this.expandCapacity(newCount); + } + str.getChars(0, len, this.buf, this.count); + this.count = newCount; + } + + public void finish() { + // do nothing + + } + + } + + private static class BinarySetQCollector implements CommandCollector { + ArrayList bufferList = new ArrayList(); + int totalBytes; + BinaryStoreCommand prevCommand; + Map mergeCommands; + + public CommandCollector reset() { + this.bufferList.clear(); + this.totalBytes = 0; + this.prevCommand = null; + this.mergeCommands = null; + return this; + } + + public Object getResult() { + byte[] buf = new byte[this.totalBytes]; + int offset = 0; + for (IoBuffer buffer : this.bufferList) { + byte[] ba = buffer.array(); + System.arraycopy(ba, 0, buf, offset, ba.length); + offset += ba.length; + } + BinarySetMultiCommand resultCommand = + new BinarySetMultiCommand(null, CommandType.SET_MANY, new CountDownLatch(1)); + resultCommand.setIoBuffer(IoBuffer.wrap(buf)); + resultCommand.setMergeCommands(this.mergeCommands); + resultCommand.setMergeCount(this.mergeCommands.size()); + return resultCommand; + } + + public void visit(Command command) { + + // Encode prev command + if (this.prevCommand != null) { + // first n-1 send setq command + BinaryStoreCommand setqCmd = + new BinaryStoreCommand(this.prevCommand.getKey(), this.prevCommand.getKeyBytes(), + CommandType.SET, null, this.prevCommand.getExpTime(), this.prevCommand.getCas(), + // set noreply to be true + this.prevCommand.getValue(), true, this.prevCommand.getTranscoder()); + // We must set the opaque to get error message. + int opaque = OpaqueGenerater.getInstance().getNextValue(); + setqCmd.setOpaque(opaque); + setqCmd.encode(); + this.totalBytes += setqCmd.getIoBuffer().remaining(); + + this.bufferList.add(setqCmd.getIoBuffer()); + // GC friendly + setqCmd.setIoBuffer(MemcachedHandler.EMPTY_BUF); + setqCmd.setValue(null); + this.prevCommand.setValue(null); + this.prevCommand.setIoBuffer(MemcachedHandler.EMPTY_BUF); + if (this.mergeCommands == null) { + this.mergeCommands = new HashMap(); + } + this.mergeCommands.put(opaque, this.prevCommand); + } + this.prevCommand = (BinaryStoreCommand) command; + } + + public void finish() { + if (this.mergeCommands == null) { + return; + } + // prevCommand is the last command,last command must be a SET + // command,ensure + // previous SETQ commands sending response back + BinaryStoreCommand setqCmd = + new BinaryStoreCommand(this.prevCommand.getKey(), this.prevCommand.getKeyBytes(), + CommandType.SET, null, this.prevCommand.getExpTime(), this.prevCommand.getCas(), + // set noreply to be false. + this.prevCommand.getValue(), false, this.prevCommand.getTranscoder()); + // We must set the opaque to get error message. + int opaque = OpaqueGenerater.getInstance().getNextValue(); + setqCmd.setOpaque(opaque); + setqCmd.encode(); + this.bufferList.add(setqCmd.getIoBuffer()); + this.totalBytes += setqCmd.getIoBuffer().remaining(); + if (this.mergeCommands != null) { + this.mergeCommands.put(opaque, this.prevCommand); + } + } + + } + + private static class BinaryGetQCollector implements CommandCollector { + ArrayList bufferList = new ArrayList(50); + int totalBytes; + Command prevCommand; + + public CommandCollector reset() { + this.bufferList.clear(); + this.totalBytes = 0; + this.prevCommand = null; + return this; + } + + public Object getResult() { + byte[] buf = new byte[this.totalBytes]; + int offset = 0; + for (IoBuffer buffer : this.bufferList) { + byte[] ba = buffer.array(); + System.arraycopy(ba, 0, buf, offset, ba.length); + offset += ba.length; + } + BinaryGetMultiCommand resultCommand = + new BinaryGetMultiCommand(null, CommandType.GET_MANY, new CountDownLatch(1)); + resultCommand.setIoBuffer(IoBuffer.wrap(buf)); + return resultCommand; + } + + public void visit(Command command) { + // Encode prev command + if (this.prevCommand != null) { + // first n-1 send getq command + Command getqCommand = new BinaryGetCommand(this.prevCommand.getKey(), + this.prevCommand.getKeyBytes(), null, null, OpCode.GET_KEY_QUIETLY, true); + getqCommand.encode(); + this.totalBytes += getqCommand.getIoBuffer().remaining(); + this.bufferList.add(getqCommand.getIoBuffer()); + } + this.prevCommand = command; + } + + public void finish() { + // prev command is the last command,last command must be getk,ensure + // getq commands sending response back + Command lastGetKCommand = + new BinaryGetCommand(this.prevCommand.getKey(), this.prevCommand.getKeyBytes(), + CommandType.GET_ONE, new CountDownLatch(1), OpCode.GET_KEY, false); + lastGetKCommand.encode(); + this.bufferList.add(lastGetKCommand.getIoBuffer()); + this.totalBytes += lastGetKCommand.getIoBuffer().remaining(); + } + + } + + @SuppressWarnings("unchecked") + private final Command mergeGetCommands(final Command currentCmd, final Queue writeQueue, + final Queue executingCmds, CommandType expectedCommandType) { + Map mergeCommands = null; + int mergeCount = 1; + final CommandCollector commandCollector = this.createGetCommandCollector(); + currentCmd.setStatus(OperationStatus.WRITING); + + commandCollector.visit(currentCmd); + while (mergeCount < this.mergeFactor) { + Command nextCmd = (Command) writeQueue.peek(); + if (nextCmd == null) { + break; + } + if (nextCmd.isCancel()) { + writeQueue.remove(); + continue; + } + if (nextCmd.getCommandType() == expectedCommandType) { + if (mergeCommands == null) { // lazy initialize + mergeCommands = new HashMap(this.mergeFactor / 2); + mergeCommands.put(currentCmd.getKey(), currentCmd); + } + if (log.isDebugEnabled()) { + log.debug("Merge get command:" + nextCmd.toString()); + } + nextCmd.setStatus(OperationStatus.WRITING); + Command removedCommand = (Command) writeQueue.remove(); + // If the key is exists,add the command to associated list. + if (mergeCommands.containsKey(removedCommand.getKey())) { + final AssocCommandAware mergedGetCommand = + (AssocCommandAware) mergeCommands.get(removedCommand.getKey()); + if (mergedGetCommand.getAssocCommands() == null) { + mergedGetCommand.setAssocCommands(new ArrayList(5)); + } + mergedGetCommand.getAssocCommands().add(removedCommand); + } else { + commandCollector.visit(nextCmd); + mergeCommands.put(removedCommand.getKey(), removedCommand); + } + mergeCount++; + } else { + break; + } + } + if (mergeCount == 1) { + return currentCmd; + } else { + commandCollector.finish(); + if (log.isDebugEnabled()) { + log.debug("Merge optimieze:merge " + mergeCount + " get commands"); + } + return this.newMergedCommand(mergeCommands, mergeCount, commandCollector, + expectedCommandType); + } + } + + private static final ThreadLocal BIN_SET_CMD_COLLECTOR_THREAD_LOCAL = + new ThreadLocal() { + + @Override + protected BinarySetQCollector initialValue() { + return new BinarySetQCollector(); + } + + }; + + private final Command mergeSetCommands(final Command currentCmd, final Queue writeQueue, + final Queue executingCmds, CommandType expectedCommandType, int sendBufferSize) { + int mergeCount = 1; + final CommandCollector commandCollector = BIN_SET_CMD_COLLECTOR_THREAD_LOCAL.get().reset(); + currentCmd.setStatus(OperationStatus.WRITING); + int totalBytes = currentCmd.getIoBuffer().remaining(); + commandCollector.visit(currentCmd); + while (mergeCount < this.mergeFactor && totalBytes <= sendBufferSize) { + Command nextCmd = (Command) writeQueue.peek(); + if (nextCmd == null) { + break; + } + if (nextCmd.isCancel()) { + writeQueue.remove(); + continue; + } + if (nextCmd.getCommandType() == expectedCommandType && !nextCmd.isNoreply()) { + if (log.isDebugEnabled()) { + log.debug("Merge set command:" + nextCmd.toString()); + } + nextCmd.setStatus(OperationStatus.WRITING); + writeQueue.remove(); + + commandCollector.visit(nextCmd); + + mergeCount++; + } else { + break; + } + totalBytes += nextCmd.getIoBuffer().remaining(); + } + if (mergeCount == 1) { + return currentCmd; + } else { + commandCollector.finish(); + if (log.isDebugEnabled()) { + log.debug("Merge optimieze:merge " + mergeCount + " get commands"); + } + return (Command) commandCollector.getResult(); + } + } + + private static ThreadLocal TEXT_GET_CMD_COLLECTOR_THREAD_LOCAL = + new ThreadLocal() { + @Override + public KeyStringCollector initialValue() { + return new KeyStringCollector(); + } + }; + + private static ThreadLocal BIN_GET_CMD_COLLECTOR_THREAD_LOCAL = + new ThreadLocal() { + @Override + public BinaryGetQCollector initialValue() { + return new BinaryGetQCollector(); + } + }; + + private CommandCollector createGetCommandCollector() { + switch (this.protocol) { + case Binary: + return BIN_GET_CMD_COLLECTOR_THREAD_LOCAL.get().reset(); + default: + return TEXT_GET_CMD_COLLECTOR_THREAD_LOCAL.get().reset(); + } + } + + private Command newMergedCommand(final Map mergeCommands, int mergeCount, + final CommandCollector commandCollector, final CommandType commandType) { + if (this.protocol == Protocol.Text) { + String resultKey = (String) commandCollector.getResult(); + + byte[] keyBytes = ByteUtils.getBytes(resultKey); + byte[] cmdBytes = commandType == CommandType.GET_ONE ? Constants.GET : Constants.GETS; + final byte[] buf = new byte[cmdBytes.length + 3 + keyBytes.length]; + ByteUtils.setArguments(buf, 0, cmdBytes, keyBytes); + TextGetOneCommand cmd = new TextGetOneCommand(resultKey, keyBytes, commandType, null); + cmd.setMergeCommands(mergeCommands); + cmd.setWriteFuture(new FutureImpl()); + cmd.setMergeCount(mergeCount); + cmd.setIoBuffer(IoBuffer.wrap(buf)); + return cmd; + } else { + BinaryGetMultiCommand result = (BinaryGetMultiCommand) commandCollector.getResult(); + result.setMergeCount(mergeCount); + result.setMergeCommands(mergeCommands); + return result; + } + } +} diff --git a/src/main/java/net/rubyeye/xmemcached/impl/OptimizerMBean.java b/src/main/java/net/rubyeye/xmemcached/impl/OptimizerMBean.java index 8847882e3..e0e8975b5 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/OptimizerMBean.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/OptimizerMBean.java @@ -1,44 +1,38 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.impl; /** * OptimizerMBean,used for changing the optimizer's factor - * + * * @author dennis - * + * */ public interface OptimizerMBean { - public int getMergeFactor(); + public int getMergeFactor(); - public boolean isOptimizeGet(); + public boolean isOptimizeGet(); - public boolean isOptimizeMergeBuffer(); + public boolean isOptimizeMergeBuffer(); - public void setMergeFactor(int mergeFactor); + public void setMergeFactor(int mergeFactor); - public void setOptimizeGet(boolean optimiezeGet); + public void setOptimizeGet(boolean optimiezeGet); - public void setOptimizeMergeBuffer(boolean optimiezeMergeBuffer); + public void setOptimizeMergeBuffer(boolean optimiezeMergeBuffer); } diff --git a/src/main/java/net/rubyeye/xmemcached/impl/PHPMemcacheSessionLocator.java b/src/main/java/net/rubyeye/xmemcached/impl/PHPMemcacheSessionLocator.java index fa56ec373..a09fbdc7b 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/PHPMemcacheSessionLocator.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/PHPMemcacheSessionLocator.java @@ -1,100 +1,94 @@ -/** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 net.rubyeye.xmemcached.impl; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import net.rubyeye.xmemcached.HashAlgorithm; -import net.rubyeye.xmemcached.networking.MemcachedSession; - -import com.google.code.yanf4j.core.Session; - -/** - * Session locator base on hash(key) mod sessions.size(). Uses the PHP memcached - * hash strategy so it's easier to share data with PHP based clients. - * - * @author aravind - * - */ -public class PHPMemcacheSessionLocator extends AbstractMemcachedSessionLocator { - - private HashAlgorithm hashAlgorithm; - private transient volatile List sessions; - - public PHPMemcacheSessionLocator() { - this.hashAlgorithm = HashAlgorithm.NATIVE_HASH; - } - - public PHPMemcacheSessionLocator(HashAlgorithm hashAlgorithm) { - this.hashAlgorithm = hashAlgorithm; - } - - public final void setHashAlgorighm(HashAlgorithm hashAlgorithm) { - this.hashAlgorithm = hashAlgorithm; - } - - public final long getHash(int size, String key) { - long hash = this.hashAlgorithm.hash(key); - hash = (hash >> 16) & 0x7fff; - return hash % size; - } - - public final Session getSessionByKey(final String key) { - if (this.sessions == null || this.sessions.size() == 0) { - return null; - } - // Copy on read - List sessionList = this.sessions; - int size = sessionList.size(); - if (size == 0) { - return null; - } - long start = this.getHash(size, key); - Session session = sessionList.get((int) start); - // If it is not failure mode,get next available session - if (!this.failureMode && (session == null || session.isClosed())) { - long next = this.getNext(size, start); - while ((session == null || session.isClosed()) && next != start) { - session = sessionList.get((int) next); - next = this.getNext(size, next); - } - } - return session; - } - - public final long getNext(int size, long start) { - if (start == size - 1) { - return 0; - } else { - return start + 1; - } - } - - public final void updateSessions(final Collection list) { - Collection copySessions = list; - List newSessions = new ArrayList( - copySessions.size() * 2); - for (Session session : copySessions) { - if (session instanceof MemcachedTCPSession) { - int weight = ((MemcachedSession) session).getWeight(); - for (int i = 0; i < weight; i++) { - newSessions.add(session); - } - } else { - newSessions.add(session); - } - } - this.sessions = newSessions; - } -} +/** + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.impl; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import net.rubyeye.xmemcached.HashAlgorithm; +import net.rubyeye.xmemcached.networking.MemcachedSession; +import com.google.code.yanf4j.core.Session; + +/** + * Session locator base on hash(key) mod sessions.size(). Uses the PHP memcached hash strategy so + * it's easier to share data with PHP based clients. + * + * @author aravind + * + */ +public class PHPMemcacheSessionLocator extends AbstractMemcachedSessionLocator { + + private HashAlgorithm hashAlgorithm; + private transient volatile List sessions; + + public PHPMemcacheSessionLocator() { + this.hashAlgorithm = HashAlgorithm.NATIVE_HASH; + } + + public PHPMemcacheSessionLocator(HashAlgorithm hashAlgorithm) { + this.hashAlgorithm = hashAlgorithm; + } + + public final void setHashAlgorighm(HashAlgorithm hashAlgorithm) { + this.hashAlgorithm = hashAlgorithm; + } + + public final long getHash(int size, String key) { + long hash = this.hashAlgorithm.hash(key); + hash = (hash >> 16) & 0x7fff; + return hash % size; + } + + public final Session getSessionByKey(final String key) { + if (this.sessions == null || this.sessions.size() == 0) { + return null; + } + // Copy on read + List sessionList = this.sessions; + int size = sessionList.size(); + if (size == 0) { + return null; + } + long start = this.getHash(size, key); + Session session = sessionList.get((int) start); + // If it is not failure mode,get next available session + if (!this.failureMode && (session == null || session.isClosed())) { + long next = this.getNext(size, start); + while ((session == null || session.isClosed()) && next != start) { + session = sessionList.get((int) next); + next = this.getNext(size, next); + } + } + return session; + } + + public final long getNext(int size, long start) { + if (start == size - 1) { + return 0; + } else { + return start + 1; + } + } + + public final void updateSessions(final Collection list) { + Collection copySessions = list; + List newSessions = new ArrayList(copySessions.size() * 2); + for (Session session : copySessions) { + if (session instanceof MemcachedTCPSession) { + int weight = ((MemcachedSession) session).getWeight(); + for (int i = 0; i < weight; i++) { + newSessions.add(session); + } + } else { + newSessions.add(session); + } + } + this.sessions = newSessions; + } +} diff --git a/src/main/java/net/rubyeye/xmemcached/impl/RandomMemcachedSessionLocaltor.java b/src/main/java/net/rubyeye/xmemcached/impl/RandomMemcachedSessionLocaltor.java index 3cb92259d..7dea861ec 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/RandomMemcachedSessionLocaltor.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/RandomMemcachedSessionLocaltor.java @@ -1,39 +1,37 @@ -package net.rubyeye.xmemcached.impl; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Random; - -import com.google.code.yanf4j.core.Session; - -import net.rubyeye.xmemcached.MemcachedSessionLocator; - -/** - * A random session locator,it can be used in kestrel. - * - * @author dennis - * - */ -public class RandomMemcachedSessionLocaltor implements MemcachedSessionLocator { - private transient volatile List sessions = Collections.emptyList(); - private final Random rand = new Random(); - - public Session getSessionByKey(String key) { - List copiedOnWrite = sessions; - if (copiedOnWrite == null || copiedOnWrite.isEmpty()) - return null; - return copiedOnWrite.get(rand.nextInt(copiedOnWrite.size())); - } - - public void updateSessions(Collection list) { - this.sessions = new ArrayList(list); - - } - - public void setFailureMode(boolean failureMode) { - // ignore - } - -} +package net.rubyeye.xmemcached.impl; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Random; +import com.google.code.yanf4j.core.Session; +import net.rubyeye.xmemcached.MemcachedSessionLocator; + +/** + * A random session locator,it can be used in kestrel. + * + * @author dennis + * + */ +public class RandomMemcachedSessionLocaltor implements MemcachedSessionLocator { + private transient volatile List sessions = Collections.emptyList(); + private final Random rand = new Random(); + + public Session getSessionByKey(String key) { + List copiedOnWrite = sessions; + if (copiedOnWrite == null || copiedOnWrite.isEmpty()) + return null; + return copiedOnWrite.get(rand.nextInt(copiedOnWrite.size())); + } + + public void updateSessions(Collection list) { + this.sessions = new ArrayList(list); + + } + + public void setFailureMode(boolean failureMode) { + // ignore + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/impl/ReconnectRequest.java b/src/main/java/net/rubyeye/xmemcached/impl/ReconnectRequest.java index 8076eb2bb..550aac55e 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/ReconnectRequest.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/ReconnectRequest.java @@ -1,30 +1,23 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.impl; import java.util.concurrent.Delayed; import java.util.concurrent.TimeUnit; - import net.rubyeye.xmemcached.utils.InetSocketAddressWrapper; /** @@ -35,81 +28,78 @@ */ public final class ReconnectRequest implements Delayed { - private InetSocketAddressWrapper inetSocketAddressWrapper; - private int tries; - - private static final long MIN_RECONNECT_INTERVAL = 1000; - - private static final long MAX_RECONNECT_INTERVAL = 60 * 1000; - - private volatile long nextReconnectTimestamp; - - public ReconnectRequest(InetSocketAddressWrapper inetSocketAddressWrapper, - int tries, long reconnectInterval) { - super(); - this.setInetSocketAddressWrapper(inetSocketAddressWrapper); - this.setTries(tries); // record reconnect times - reconnectInterval = this.normalInterval(reconnectInterval); - this.nextReconnectTimestamp = System.currentTimeMillis() - + reconnectInterval; - } - - private long normalInterval(long reconnectInterval) { - if (reconnectInterval < MIN_RECONNECT_INTERVAL) { - reconnectInterval = MIN_RECONNECT_INTERVAL; - } - if (reconnectInterval > MAX_RECONNECT_INTERVAL) { - reconnectInterval = MAX_RECONNECT_INTERVAL; - } - return reconnectInterval; - } - - public long getDelay(TimeUnit unit) { - return unit.convert( - this.nextReconnectTimestamp - System.currentTimeMillis(), - TimeUnit.MILLISECONDS); - } - - public int compareTo(Delayed o) { - ReconnectRequest other = (ReconnectRequest) o; - if (this.nextReconnectTimestamp > other.nextReconnectTimestamp) { - return 1; - } else { - return -1; - } - } - - /** - * Returns a reconnect socket address wrapper - * - * @see InetSocketAddressWrapper - * @return - */ - public final InetSocketAddressWrapper getInetSocketAddressWrapper() { - return this.inetSocketAddressWrapper; - } - - public void updateNextReconnectTimeStamp(long interval) { - interval = this.normalInterval(interval); - this.nextReconnectTimestamp = System.currentTimeMillis() + interval; - } - - public final void setInetSocketAddressWrapper( - InetSocketAddressWrapper inetSocketAddressWrapper) { - this.inetSocketAddressWrapper = inetSocketAddressWrapper; - } - - public final void setTries(int tries) { - this.tries = tries; - } - - /** - * Returns retry times - * - * @return retry times,it is zero if it does not retry to connect - */ - public final int getTries() { - return this.tries; - } - -} \ No newline at end of file + private InetSocketAddressWrapper inetSocketAddressWrapper; + private int tries; + + private static final long MIN_RECONNECT_INTERVAL = 1000; + + private static final long MAX_RECONNECT_INTERVAL = 60 * 1000; + + private volatile long nextReconnectTimestamp; + + public ReconnectRequest(InetSocketAddressWrapper inetSocketAddressWrapper, int tries, + long reconnectInterval) { + super(); + this.setInetSocketAddressWrapper(inetSocketAddressWrapper); + this.setTries(tries); // record reconnect times + reconnectInterval = this.normalInterval(reconnectInterval); + this.nextReconnectTimestamp = System.currentTimeMillis() + reconnectInterval; + } + + private long normalInterval(long reconnectInterval) { + if (reconnectInterval < MIN_RECONNECT_INTERVAL) { + reconnectInterval = MIN_RECONNECT_INTERVAL; + } + if (reconnectInterval > MAX_RECONNECT_INTERVAL) { + reconnectInterval = MAX_RECONNECT_INTERVAL; + } + return reconnectInterval; + } + + public long getDelay(TimeUnit unit) { + return unit.convert(this.nextReconnectTimestamp - System.currentTimeMillis(), + TimeUnit.MILLISECONDS); + } + + public int compareTo(Delayed o) { + ReconnectRequest other = (ReconnectRequest) o; + if (this.nextReconnectTimestamp > other.nextReconnectTimestamp) { + return 1; + } else { + return -1; + } + } + + /** + * Returns a reconnect socket address wrapper + * + * @see InetSocketAddressWrapper + * @return + */ + public final InetSocketAddressWrapper getInetSocketAddressWrapper() { + return this.inetSocketAddressWrapper; + } + + public void updateNextReconnectTimeStamp(long interval) { + interval = this.normalInterval(interval); + this.nextReconnectTimestamp = System.currentTimeMillis() + interval; + } + + public final void setInetSocketAddressWrapper(InetSocketAddressWrapper inetSocketAddressWrapper) { + this.inetSocketAddressWrapper = inetSocketAddressWrapper; + } + + public final void setTries(int tries) { + this.tries = tries; + } + + /** + * Returns retry times + * + * @return retry times,it is zero if it does not retry to connect + */ + public final int getTries() { + return this.tries; + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/impl/RoundRobinMemcachedSessionLocator.java b/src/main/java/net/rubyeye/xmemcached/impl/RoundRobinMemcachedSessionLocator.java index 7d903b23b..0e5a22d1c 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/RoundRobinMemcachedSessionLocator.java +++ b/src/main/java/net/rubyeye/xmemcached/impl/RoundRobinMemcachedSessionLocator.java @@ -1,57 +1,51 @@ -package net.rubyeye.xmemcached.impl; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -import com.google.code.yanf4j.core.Session; - -import net.rubyeye.xmemcached.MemcachedSessionLocator; -import net.rubyeye.xmemcached.networking.MemcachedSession; - -/** - * A round-robin session locator for some special applications,memcacheq or - * kestrel etc.They doesn't need the same key must always to be stored in same - * memcached but want to make a cluster. - * - * @author apple - * - */ -public class RoundRobinMemcachedSessionLocator - implements - MemcachedSessionLocator { - private transient volatile List sessions; - private AtomicInteger sets = new AtomicInteger(0); - - public Session getSessionByKey(String key) { - List copyList = this.sessions; - if (copyList == null || copyList.isEmpty()) - return null; - int size = copyList.size(); - return copyList.get(Math.abs(sets.getAndIncrement()) % size); - } - - public final void updateSessions(final Collection list) { - Collection copySessions = list; - List newSessions = new ArrayList( - copySessions.size() * 2); - for (Session session : copySessions) { - if (session instanceof MemcachedTCPSession) { - int weight = ((MemcachedSession) session).getWeight(); - for (int i = 0; i < weight; i++) { - newSessions.add(session); - } - } else { - newSessions.add(session); - } - } - this.sessions = newSessions; - } - - public void setFailureMode(boolean failureMode) { - // ignore - - } - -} +package net.rubyeye.xmemcached.impl; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import com.google.code.yanf4j.core.Session; +import net.rubyeye.xmemcached.MemcachedSessionLocator; +import net.rubyeye.xmemcached.networking.MemcachedSession; + +/** + * A round-robin session locator for some special applications,memcacheq or kestrel etc.They doesn't + * need the same key must always to be stored in same memcached but want to make a cluster. + * + * @author apple + * + */ +public class RoundRobinMemcachedSessionLocator implements MemcachedSessionLocator { + private transient volatile List sessions; + private AtomicInteger sets = new AtomicInteger(0); + + public Session getSessionByKey(String key) { + List copyList = this.sessions; + if (copyList == null || copyList.isEmpty()) + return null; + int size = copyList.size(); + return copyList.get(Math.abs(sets.getAndIncrement()) % size); + } + + public final void updateSessions(final Collection list) { + Collection copySessions = list; + List newSessions = new ArrayList(copySessions.size() * 2); + for (Session session : copySessions) { + if (session instanceof MemcachedTCPSession) { + int weight = ((MemcachedSession) session).getWeight(); + for (int i = 0; i < weight; i++) { + newSessions.add(session); + } + } else { + newSessions.add(session); + } + } + this.sessions = newSessions; + } + + public void setFailureMode(boolean failureMode) { + // ignore + + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/impl/package.html b/src/main/java/net/rubyeye/xmemcached/impl/package.html index 558737ab6..ce8d5a6d6 100644 --- a/src/main/java/net/rubyeye/xmemcached/impl/package.html +++ b/src/main/java/net/rubyeye/xmemcached/impl/package.html @@ -1,15 +1,10 @@ - - + - -Memcached Implementation - - - -

Manage tcp connection,memcached protocol optimized,and some -MBeans for monitor.

- - - + + Memcached Implementation + + +

Manage tcp connection,memcached protocol optimized,and some MBeans for monitor.

+ + \ No newline at end of file diff --git a/src/main/java/net/rubyeye/xmemcached/monitor/Constants.java b/src/main/java/net/rubyeye/xmemcached/monitor/Constants.java index 3252f41b1..50e55b741 100644 --- a/src/main/java/net/rubyeye/xmemcached/monitor/Constants.java +++ b/src/main/java/net/rubyeye/xmemcached/monitor/Constants.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.monitor; @@ -31,41 +25,40 @@ * */ public class Constants { - /** - * Whether to enable client statisitics - */ - public static final String XMEMCACHED_STATISTICS_ENABLE = "xmemcached.statistics.enable"; - /** - * JMX RMI service name - * - */ - public static final String XMEMCACHED_RMI_NAME = "xmemcached.rmi.name"; - /** - * JMX RMI port - * - * - */ - public static final String XMEMCACHED_RMI_PORT = "xmemcached.rmi.port"; - /** - * Whether to enable jmx supports - */ - public static final String XMEMCACHED_JMX_ENABLE = "xmemcached.jmx.enable"; - public static final byte[] CRLF = {'\r', '\n'}; - public static final byte[] GET = {'g', 'e', 't'}; - public static final byte[] GETS = {'g', 'e', 't', 's'}; - public static final byte SPACE = ' '; - public static final byte[] INCR = {'i', 'n', 'c', 'r'}; - public static final byte[] DECR = {'d', 'e', 'c', 'r'}; - public static final byte[] DELETE = {'d', 'e', 'l', 'e', 't', 'e'}; - public static final byte[] TOUCH = {'t', 'o', 'u', 'c', 'h'}; - /** - * Max session read buffer size,758k - */ - public static final int MAX_SESSION_READ_BUFFER_SIZE = 768 * 1024; - public static final byte[] NO_REPLY = {'n', 'o', 'r', 'e', 'p', 'l', 'y'}; - /** - * Client instance counter - */ - public static final AtomicInteger MEMCACHED_CLIENT_COUNTER = new AtomicInteger( - 0); + /** + * Whether to enable client statisitics + */ + public static final String XMEMCACHED_STATISTICS_ENABLE = "xmemcached.statistics.enable"; + /** + * JMX RMI service name + * + */ + public static final String XMEMCACHED_RMI_NAME = "xmemcached.rmi.name"; + /** + * JMX RMI port + * + * + */ + public static final String XMEMCACHED_RMI_PORT = "xmemcached.rmi.port"; + /** + * Whether to enable jmx supports + */ + public static final String XMEMCACHED_JMX_ENABLE = "xmemcached.jmx.enable"; + public static final byte[] CRLF = {'\r', '\n'}; + public static final byte[] GET = {'g', 'e', 't'}; + public static final byte[] GETS = {'g', 'e', 't', 's'}; + public static final byte SPACE = ' '; + public static final byte[] INCR = {'i', 'n', 'c', 'r'}; + public static final byte[] DECR = {'d', 'e', 'c', 'r'}; + public static final byte[] DELETE = {'d', 'e', 'l', 'e', 't', 'e'}; + public static final byte[] TOUCH = {'t', 'o', 'u', 'c', 'h'}; + /** + * Max session read buffer size,758k + */ + public static final int MAX_SESSION_READ_BUFFER_SIZE = 768 * 1024; + public static final byte[] NO_REPLY = {'n', 'o', 'r', 'e', 'p', 'l', 'y'}; + /** + * Client instance counter + */ + public static final AtomicInteger MEMCACHED_CLIENT_COUNTER = new AtomicInteger(0); } diff --git a/src/main/java/net/rubyeye/xmemcached/monitor/MemcachedClientNameHolder.java b/src/main/java/net/rubyeye/xmemcached/monitor/MemcachedClientNameHolder.java index 4355fdf0a..347397686 100644 --- a/src/main/java/net/rubyeye/xmemcached/monitor/MemcachedClientNameHolder.java +++ b/src/main/java/net/rubyeye/xmemcached/monitor/MemcachedClientNameHolder.java @@ -1,24 +1,24 @@ -package net.rubyeye.xmemcached.monitor; - -/** - * MemcachedClient insntance name holder - * - * @author dennis - * - */ -public class MemcachedClientNameHolder { - private static ThreadLocal cacheName = new ThreadLocal(); - - public static void setName(String name) { - cacheName.set(name); - } - - public static String getName() { - return cacheName.get(); - } - - public static void clear() { - cacheName.remove(); - } - -} +package net.rubyeye.xmemcached.monitor; + +/** + * MemcachedClient insntance name holder + * + * @author dennis + * + */ +public class MemcachedClientNameHolder { + private static ThreadLocal cacheName = new ThreadLocal(); + + public static void setName(String name) { + cacheName.set(name); + } + + public static String getName() { + return cacheName.get(); + } + + public static void clear() { + cacheName.remove(); + } + +} diff --git a/src/main/java/net/rubyeye/xmemcached/monitor/StatisticsHandler.java b/src/main/java/net/rubyeye/xmemcached/monitor/StatisticsHandler.java index 11a7c7780..a3eb45bce 100644 --- a/src/main/java/net/rubyeye/xmemcached/monitor/StatisticsHandler.java +++ b/src/main/java/net/rubyeye/xmemcached/monitor/StatisticsHandler.java @@ -1,31 +1,24 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.monitor; import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; - import net.rubyeye.xmemcached.command.CommandType; /** @@ -35,119 +28,117 @@ * */ public class StatisticsHandler implements StatisticsHandlerMBean { - private Map counterMap = new HashMap(); - - public StatisticsHandler() { - buildCounterMap(); - XMemcachedMbeanServer.getInstance().registMBean(this, - this.getClass().getPackage().getName() + ":type=" - + this.getClass().getSimpleName() + "-" - + MemcachedClientNameHolder.getName()); - } - - private boolean statistics = Boolean.valueOf(System - .getProperty(Constants.XMEMCACHED_STATISTICS_ENABLE, "false")); - - private void buildCounterMap() { - if (this.statistics) { - Map map = new HashMap(); - map.put(CommandType.APPEND, new AtomicLong()); - map.put(CommandType.SET, new AtomicLong()); - map.put(CommandType.SET_MANY, new AtomicLong()); - map.put(CommandType.PREPEND, new AtomicLong()); - map.put(CommandType.CAS, new AtomicLong()); - map.put(CommandType.ADD, new AtomicLong()); - map.put(CommandType.REPLACE, new AtomicLong()); - map.put(CommandType.DELETE, new AtomicLong()); - map.put(CommandType.INCR, new AtomicLong()); - map.put(CommandType.DECR, new AtomicLong()); - map.put(CommandType.GET_HIT, new AtomicLong()); - map.put(CommandType.GET_MISS, new AtomicLong()); - map.put(CommandType.GET_MANY, new AtomicLong()); - map.put(CommandType.GETS_MANY, new AtomicLong()); - this.counterMap = map; - } - } - - public final boolean isStatistics() { - return this.statistics; - } - - public final void statistics(CommandType cmdType) { - if (this.statistics && this.counterMap.get(cmdType) != null) { - this.counterMap.get(cmdType).incrementAndGet(); - } - } - - public final void statistics(CommandType cmdType, int count) { - if (this.statistics && this.counterMap.get(cmdType) != null) { - this.counterMap.get(cmdType).addAndGet(count); - } - } - - public final void setStatistics(boolean statistics) { - this.statistics = statistics; - buildCounterMap(); - - } - - public void resetStats() { - if (this.statistics) { - buildCounterMap(); - } - } - - public long getAppendCount() { - return this.counterMap.get(CommandType.APPEND).get(); - } - - public long getCASCount() { - return this.counterMap.get(CommandType.CAS).get(); - } - - public long getDecrCount() { - return this.counterMap.get(CommandType.DECR).get(); - } - - public long getDeleteCount() { - return this.counterMap.get(CommandType.DELETE).get(); - } - - public long getGetHitCount() { - return this.counterMap.get(CommandType.GET_HIT).get(); - } - - public long getGetMissCount() { - return this.counterMap.get(CommandType.GET_MISS).get(); - } - - public long getIncrCount() { - return this.counterMap.get(CommandType.INCR).get(); - } - - public long getMultiGetCount() { - return this.counterMap.get(CommandType.GET_MANY).get(); - } - - public long getMultiGetsCount() { - return this.counterMap.get(CommandType.GETS_MANY).get(); - } - - public long getPrependCount() { - return this.counterMap.get(CommandType.PREPEND).get(); - } - - public long getSetCount() { - return this.counterMap.get(CommandType.SET).get() - + this.counterMap.get(CommandType.SET_MANY).get(); - } - - public long getAddCount() { - return this.counterMap.get(CommandType.ADD).get(); - } - - public long getReplaceCount() { - return this.counterMap.get(CommandType.REPLACE).get(); - } + private Map counterMap = new HashMap(); + + public StatisticsHandler() { + buildCounterMap(); + XMemcachedMbeanServer.getInstance().registMBean(this, this.getClass().getPackage().getName() + + ":type=" + this.getClass().getSimpleName() + "-" + MemcachedClientNameHolder.getName()); + } + + private boolean statistics = + Boolean.valueOf(System.getProperty(Constants.XMEMCACHED_STATISTICS_ENABLE, "false")); + + private void buildCounterMap() { + if (this.statistics) { + Map map = new HashMap(); + map.put(CommandType.APPEND, new AtomicLong()); + map.put(CommandType.SET, new AtomicLong()); + map.put(CommandType.SET_MANY, new AtomicLong()); + map.put(CommandType.PREPEND, new AtomicLong()); + map.put(CommandType.CAS, new AtomicLong()); + map.put(CommandType.ADD, new AtomicLong()); + map.put(CommandType.REPLACE, new AtomicLong()); + map.put(CommandType.DELETE, new AtomicLong()); + map.put(CommandType.INCR, new AtomicLong()); + map.put(CommandType.DECR, new AtomicLong()); + map.put(CommandType.GET_HIT, new AtomicLong()); + map.put(CommandType.GET_MISS, new AtomicLong()); + map.put(CommandType.GET_MANY, new AtomicLong()); + map.put(CommandType.GETS_MANY, new AtomicLong()); + this.counterMap = map; + } + } + + public final boolean isStatistics() { + return this.statistics; + } + + public final void statistics(CommandType cmdType) { + if (this.statistics && this.counterMap.get(cmdType) != null) { + this.counterMap.get(cmdType).incrementAndGet(); + } + } + + public final void statistics(CommandType cmdType, int count) { + if (this.statistics && this.counterMap.get(cmdType) != null) { + this.counterMap.get(cmdType).addAndGet(count); + } + } + + public final void setStatistics(boolean statistics) { + this.statistics = statistics; + buildCounterMap(); + + } + + public void resetStats() { + if (this.statistics) { + buildCounterMap(); + } + } + + public long getAppendCount() { + return this.counterMap.get(CommandType.APPEND).get(); + } + + public long getCASCount() { + return this.counterMap.get(CommandType.CAS).get(); + } + + public long getDecrCount() { + return this.counterMap.get(CommandType.DECR).get(); + } + + public long getDeleteCount() { + return this.counterMap.get(CommandType.DELETE).get(); + } + + public long getGetHitCount() { + return this.counterMap.get(CommandType.GET_HIT).get(); + } + + public long getGetMissCount() { + return this.counterMap.get(CommandType.GET_MISS).get(); + } + + public long getIncrCount() { + return this.counterMap.get(CommandType.INCR).get(); + } + + public long getMultiGetCount() { + return this.counterMap.get(CommandType.GET_MANY).get(); + } + + public long getMultiGetsCount() { + return this.counterMap.get(CommandType.GETS_MANY).get(); + } + + public long getPrependCount() { + return this.counterMap.get(CommandType.PREPEND).get(); + } + + public long getSetCount() { + return this.counterMap.get(CommandType.SET).get() + + this.counterMap.get(CommandType.SET_MANY).get(); + } + + public long getAddCount() { + return this.counterMap.get(CommandType.ADD).get(); + } + + public long getReplaceCount() { + return this.counterMap.get(CommandType.REPLACE).get(); + } } diff --git a/src/main/java/net/rubyeye/xmemcached/monitor/StatisticsHandlerMBean.java b/src/main/java/net/rubyeye/xmemcached/monitor/StatisticsHandlerMBean.java index af6d45613..4b7b02300 100644 --- a/src/main/java/net/rubyeye/xmemcached/monitor/StatisticsHandlerMBean.java +++ b/src/main/java/net/rubyeye/xmemcached/monitor/StatisticsHandlerMBean.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.monitor; @@ -29,41 +23,41 @@ * */ public interface StatisticsHandlerMBean { - public long getGetHitCount(); + public long getGetHitCount(); - public long getGetMissCount(); + public long getGetMissCount(); - public long getSetCount(); + public long getSetCount(); - public long getAppendCount(); + public long getAppendCount(); - public long getPrependCount(); + public long getPrependCount(); - public long getCASCount(); + public long getCASCount(); - public long getDeleteCount(); + public long getDeleteCount(); - public long getIncrCount(); + public long getIncrCount(); - public long getDecrCount(); + public long getDecrCount(); - public long getMultiGetCount(); + public long getMultiGetCount(); - public long getMultiGetsCount(); + public long getMultiGetsCount(); - public long getAddCount(); + public long getAddCount(); - public long getReplaceCount(); + public long getReplaceCount(); - public boolean isStatistics(); + public boolean isStatistics(); - public void setStatistics(boolean statistics); + public void setStatistics(boolean statistics); - /** - * Reset the statistics - * - * @since 1.3.9 - */ - public void resetStats(); + /** + * Reset the statistics + * + * @since 1.3.9 + */ + public void resetStats(); } diff --git a/src/main/java/net/rubyeye/xmemcached/monitor/XMemcachedMbeanServer.java b/src/main/java/net/rubyeye/xmemcached/monitor/XMemcachedMbeanServer.java index b9cb93330..2dc82ffed 100644 --- a/src/main/java/net/rubyeye/xmemcached/monitor/XMemcachedMbeanServer.java +++ b/src/main/java/net/rubyeye/xmemcached/monitor/XMemcachedMbeanServer.java @@ -1,24 +1,18 @@ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 */ /** - *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] - *Licensed 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 + * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed 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 net.rubyeye.xmemcached.monitor; @@ -27,13 +21,11 @@ import java.net.InetAddress; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; - import javax.management.MBeanServer; import javax.management.ObjectName; import javax.management.remote.JMXConnectorServer; import javax.management.remote.JMXConnectorServerFactory; import javax.management.remote.JMXServiceURL; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -47,8 +39,8 @@ * *   service:jmx:rmi:///jndi/rmi://[host]:7077/xmemcachedServer
* - * You can add or remove memcached server dynamically and monitor - * XmemcachedClient?'s behavior through MBeans.Other options:
+ * You can add or remove memcached server dynamically and monitor XmemcachedClient?'s behavior + * through MBeans.Other options:
*