├── LICENSE.txt
├── README.md
├── codis-client
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── io
│ │ └── codis
│ │ └── nedis
│ │ └── codis
│ │ ├── BoundedExponentialBackoffRetryUntilElapsed.java
│ │ ├── CodisProxyInfo.java
│ │ └── RoundRobinNedisClientPool.java
│ └── test
│ └── java
│ └── io
│ └── codis
│ └── nedis
│ └── codis
│ ├── TestBoundedExponentialBackoffRetryUntilElapsed.java
│ ├── TestRoundRobinJedisPool.java
│ └── ZooKeeperServerWapper.java
├── jedis-LICENSE.txt
├── nedis-bench
├── assembly
│ ├── assembly.xml
│ └── bin
│ │ └── bench.sh
├── pom.xml
└── src
│ └── main
│ └── java
│ └── io
│ └── codis
│ └── nedis
│ └── bench
│ ├── JedisBench.java
│ └── NedisBench.java
├── nedis-client
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── io
│ │ └── codis
│ │ └── nedis
│ │ ├── AsyncCloseable.java
│ │ ├── ConnectionManagement.java
│ │ ├── NedisClient.java
│ │ ├── NedisClientBuilder.java
│ │ ├── NedisClientImpl.java
│ │ ├── NedisClientPool.java
│ │ ├── NedisClientPoolBuilder.java
│ │ ├── NedisClientPoolImpl.java
│ │ ├── PromiseConverter.java
│ │ ├── exception
│ │ ├── RedisResponseException.java
│ │ ├── TxnAbortException.java
│ │ └── TxnDiscardException.java
│ │ ├── handler
│ │ ├── RedisDuplexHandler.java
│ │ ├── RedisRequest.java
│ │ ├── RedisRequestEncoder.java
│ │ ├── RedisResponseDecoder.java
│ │ └── TxnRedisRequest.java
│ │ ├── protocol
│ │ ├── Aggregate.java
│ │ ├── BitOp.java
│ │ ├── BlockingListsCommands.java
│ │ ├── ConnectionCommands.java
│ │ ├── HashEntry.java
│ │ ├── HashesCommands.java
│ │ ├── HyperLogLogCommands.java
│ │ ├── KeysCommands.java
│ │ ├── ListsCommands.java
│ │ ├── RedisCommand.java
│ │ ├── RedisKeyword.java
│ │ ├── ScanParams.java
│ │ ├── ScanResult.java
│ │ ├── ScriptingCommands.java
│ │ ├── ServerCommands.java
│ │ ├── SetParams.java
│ │ ├── SetsCommands.java
│ │ ├── SortParams.java
│ │ ├── SortedSetEntry.java
│ │ ├── SortedSetsCommands.java
│ │ ├── StringsCommands.java
│ │ ├── TransactionsCommands.java
│ │ └── ZSetOpParams.java
│ │ └── util
│ │ ├── AbstractNedisBuilder.java
│ │ ├── NedisClientHashSet.java
│ │ └── NedisUtils.java
│ └── test
│ └── java
│ └── io
│ └── codis
│ └── nedis
│ ├── RedisServer.java
│ ├── TestCommands.java
│ ├── TestNedis.java
│ ├── TestNedisClientImpl.java
│ ├── TestUtils.java
│ └── util
│ └── TestNedisClientHashSet.java
└── pom.xml
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # nedis
2 | An event-driven, asynchronous redis client based on [netty](http://netty.io/)
3 |
4 | ## How to use
5 | Add this to your pom.xml. We deploy nedis to https://oss.sonatype.org.
6 | ```xml
7 |
8 | com.wandoulabs.nedis
9 | nedis-client
10 | 0.1.1
11 |
12 | ```
13 | To use it
14 | ```java
15 | NedisClientPool nedisPool = NedisClientPoolBuilder.create().timeoutMs(5000)
16 | .remoteAddress("rediserver", 6379).build();
17 | NedisClient nedis = NedisUtils.newPooledClient(nedisPool);
18 | nedis.set(NedisUtils.toBytes("foo"), NedisUtils.toBytes("bar")).sync();
19 | byte[] value = nedis.get(NedisUtils.toBytes("foo")).sync().getNow();
20 | System.out.println(NedisUtils.bytesToString(value));
21 | nedis.close().sync();
22 | ```
23 |
24 | **Java7 is required to build or use nedis.**
25 |
26 | ## For codis users
27 | Add this to your pom.xml.
28 | ```xml
29 |
30 | com.wandoulabs.nedis
31 | codis-client
32 | 0.1.1
33 |
34 | ```
35 | To use it
36 | ```java
37 | RoundRobinNedisClientPool nedisPool = RoundRobinNedisClientPool.builder()
38 | .poolBuilder(NedisClientPoolBuilder.create().timeoutMs(5000)).curatorClient("zkserver:2181", 30000)
39 | .zkProxyDir("/zk/codis/db_xxx/proxy").build().sync().getNow();
40 | NedisClient nedis = NedisUtils.newPooledClient(nedisPool);
41 | nedis.set(NedisUtils.toBytes("foo"), NedisUtils.toBytes("bar")).sync();
42 | byte[] value = nedis.get(NedisUtils.toBytes("foo")).sync().getNow();
43 | System.out.println(NedisUtils.bytesToString(value));
44 | nedis.close().sync();
45 | ```
46 |
47 | ## Performance
48 | Nedis is **NOT** faster than jedis, especially if you use it in a synchronized way. In nedis, the requests on the same connection will be pipelined automatically if possible, but it is still **NOT** faster than jedis if you explicitly use a pipeline when using jedis.
49 |
50 | So please use nedis with caution.
51 |
52 | If you are an expert of netty, you could try to use `EpollEventLoopGroup` and add `-Dio.netty.allocator.type=pooled`(default is `unpooled` in netty 4.0) when starting to increase performance.
53 |
--------------------------------------------------------------------------------
/codis-client/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | nedis
6 | io.codis.nedis
7 | 0.2.0-SNAPSHOT
8 |
9 | io.codis.nedis
10 | codis-client
11 | 0.2.0-SNAPSHOT
12 | jar
13 |
14 | UTF-8
15 | 1.7
16 | UTF-8
17 | UTF-8
18 | UTF-8
19 | UTF-8
20 |
21 |
22 |
23 | io.codis.nedis
24 | nedis-client
25 |
26 |
27 | com.fasterxml.jackson.core
28 | jackson-databind
29 |
30 |
31 | org.slf4j
32 | slf4j-api
33 |
34 |
35 | org.apache.curator
36 | curator-recipes
37 |
38 |
39 | org.slf4j
40 | slf4j-simple
41 | test
42 |
43 |
44 | org.hamcrest
45 | hamcrest-library
46 | test
47 |
48 |
49 | junit
50 | junit
51 | test
52 |
53 |
54 | org.mockito
55 | mockito-core
56 | test
57 |
58 |
59 | com.google.guava
60 | guava
61 | test
62 |
63 |
64 | io.codis.nedis
65 | nedis-client
66 | test-jar
67 | test
68 |
69 |
70 |
71 |
72 |
73 | org.apache.maven.plugins
74 | maven-source-plugin
75 | 2.4
76 |
77 |
78 | attach-sources
79 |
80 | jar-no-fork
81 |
82 |
83 |
84 |
85 |
86 | org.apache.maven.plugins
87 | maven-javadoc-plugin
88 | 2.10.3
89 |
90 |
91 | attach-javadocs
92 |
93 | jar
94 |
95 |
96 | -Xdoclint:none
97 |
98 |
99 |
100 |
101 |
102 | org.apache.maven.plugins
103 | maven-deploy-plugin
104 | 2.8.2
105 |
106 |
107 | deploy
108 | deploy
109 |
110 | deploy
111 |
112 |
113 |
114 | default-deploy
115 |
116 | true
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/codis-client/src/main/java/io/codis/nedis/codis/BoundedExponentialBackoffRetryUntilElapsed.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 CodisLabs.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.codis.nedis.codis;
17 |
18 | import java.util.concurrent.ThreadLocalRandom;
19 | import java.util.concurrent.TimeUnit;
20 |
21 | import org.apache.curator.RetryPolicy;
22 | import org.apache.curator.RetrySleeper;
23 |
24 | /**
25 | * Similar to {@link org.apache.curator.retry.BoundedExponentialBackoffRetry},
26 | * but limit the retry elapsed time, not retry number.
27 | *
28 | * @author Apache9
29 | */
30 | public class BoundedExponentialBackoffRetryUntilElapsed implements RetryPolicy {
31 |
32 | private final int baseSleepTimeMs;
33 |
34 | private final int maxSleepTimeMs;
35 |
36 | private final long maxElapsedTimeMs;
37 |
38 | /**
39 | * @param baseSleepTimeMs
40 | * initial amount of time to wait between retries
41 | * @param maxSleepTimeMs
42 | * max time in ms to sleep on each retry
43 | * @param maxElapsedTimeMs
44 | * total time in ms to retry
45 | */
46 | public BoundedExponentialBackoffRetryUntilElapsed(int baseSleepTimeMs, int maxSleepTimeMs,
47 | long maxElapsedTimeMs) {
48 | this.baseSleepTimeMs = baseSleepTimeMs;
49 | this.maxSleepTimeMs = maxSleepTimeMs;
50 | if (maxElapsedTimeMs < 0) {
51 | this.maxElapsedTimeMs = Long.MAX_VALUE;
52 | } else {
53 | this.maxElapsedTimeMs = maxElapsedTimeMs;
54 | }
55 | }
56 |
57 | private long getSleepTimeMs(int retryCount, long elapsedTimeMs) {
58 | return Math.min(
59 | maxSleepTimeMs,
60 | (long) baseSleepTimeMs
61 | * Math.max(
62 | 1,
63 | ThreadLocalRandom.current().nextInt(
64 | 1 << Math.min(30, retryCount + 1))));
65 | }
66 |
67 | @Override
68 | public boolean allowRetry(int retryCount, long elapsedTimeMs, RetrySleeper sleeper) {
69 | if (elapsedTimeMs >= maxElapsedTimeMs) {
70 | return false;
71 | }
72 | long sleepTimeMs = Math.min(maxElapsedTimeMs - elapsedTimeMs,
73 | getSleepTimeMs(retryCount, elapsedTimeMs));
74 | try {
75 | sleeper.sleepFor(sleepTimeMs, TimeUnit.MILLISECONDS);
76 | } catch (InterruptedException e) {
77 | Thread.currentThread().interrupt();
78 | return false;
79 | }
80 | return true;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/codis-client/src/main/java/io/codis/nedis/codis/CodisProxyInfo.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 CodisLabs.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.codis.nedis.codis;
17 |
18 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
19 |
20 | /**
21 | * @author Apache9
22 | */
23 | @JsonIgnoreProperties(ignoreUnknown = true)
24 | public class CodisProxyInfo {
25 |
26 | private String addr;
27 |
28 | private String state;
29 |
30 | public String getAddr() {
31 | return addr;
32 | }
33 |
34 | public void setAddr(String addr) {
35 | this.addr = addr;
36 | }
37 |
38 | public String getState() {
39 | return state;
40 | }
41 |
42 | public void setState(String state) {
43 | this.state = state;
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/codis-client/src/test/java/io/codis/nedis/codis/TestBoundedExponentialBackoffRetryUntilElapsed.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 CodisLabs.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.codis.nedis.codis;
17 |
18 | import static org.junit.Assert.*;
19 |
20 | import java.util.concurrent.ThreadLocalRandom;
21 | import java.util.concurrent.TimeUnit;
22 |
23 | import org.apache.curator.RetrySleeper;
24 | import org.junit.Test;
25 |
26 | import io.codis.nedis.codis.BoundedExponentialBackoffRetryUntilElapsed;
27 |
28 | /**
29 | * @author Apache9
30 | */
31 | public class TestBoundedExponentialBackoffRetryUntilElapsed {
32 |
33 | private static final class FakeRetrySleeper implements RetrySleeper {
34 |
35 | public long sleepTimeMs;
36 |
37 | @Override
38 | public void sleepFor(long time, TimeUnit unit) {
39 | this.sleepTimeMs = unit.toMillis(time);
40 | }
41 |
42 | }
43 |
44 | @Test
45 | public void test() {
46 | FakeRetrySleeper sleeper = new FakeRetrySleeper();
47 | BoundedExponentialBackoffRetryUntilElapsed r = new BoundedExponentialBackoffRetryUntilElapsed(
48 | 10, 2000, 60000);
49 | for (int i = 0; i < 100; i++) {
50 | assertTrue(r.allowRetry(i, ThreadLocalRandom.current().nextInt(60000), sleeper));
51 | System.out.println(sleeper.sleepTimeMs);
52 | assertTrue(sleeper.sleepTimeMs <= 2000);
53 | }
54 | assertTrue(r.allowRetry(1000, 59900, sleeper));
55 | System.out.println(sleeper.sleepTimeMs);
56 | assertTrue(sleeper.sleepTimeMs <= 100);
57 | sleeper.sleepTimeMs = -1L;
58 | assertFalse(r.allowRetry(1, 60000, sleeper));
59 | assertEquals(-1L, sleeper.sleepTimeMs);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/codis-client/src/test/java/io/codis/nedis/codis/TestRoundRobinJedisPool.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 CodisLabs.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.codis.nedis.codis;
17 |
18 | import static io.codis.nedis.TestUtils.probeFreePort;
19 | import static io.codis.nedis.TestUtils.waitUntilRedisUp;
20 | import static io.codis.nedis.util.NedisUtils.*;
21 | import static org.junit.Assert.assertEquals;
22 | import static org.junit.Assert.assertTrue;
23 |
24 | import java.io.File;
25 | import java.io.IOException;
26 | import java.nio.file.FileVisitResult;
27 | import java.nio.file.Files;
28 | import java.nio.file.Path;
29 | import java.nio.file.SimpleFileVisitor;
30 | import java.nio.file.attribute.BasicFileAttributes;
31 |
32 | import org.apache.zookeeper.CreateMode;
33 | import org.apache.zookeeper.KeeperException;
34 | import org.apache.zookeeper.ZooDefs;
35 | import org.apache.zookeeper.ZooKeeper;
36 | import org.junit.After;
37 | import org.junit.Before;
38 | import org.junit.Test;
39 |
40 | import com.fasterxml.jackson.databind.ObjectMapper;
41 | import com.fasterxml.jackson.databind.node.ObjectNode;
42 |
43 | import io.codis.nedis.NedisClient;
44 | import io.codis.nedis.NedisClientPoolBuilder;
45 | import io.codis.nedis.RedisServer;
46 | import io.codis.nedis.codis.RoundRobinNedisClientPool;
47 | import io.codis.nedis.util.NedisUtils;
48 |
49 | /**
50 | * @author Apache9
51 | */
52 | public class TestRoundRobinJedisPool {
53 |
54 | private ObjectMapper mapper = new ObjectMapper();
55 |
56 | private int zkPort;
57 |
58 | private File testDir = new File(getClass().getName());
59 |
60 | private ZooKeeperServerWapper zkServer;
61 |
62 | private int redisPort1;
63 |
64 | private RedisServer redis1;
65 |
66 | private int redisPort2;
67 |
68 | private RedisServer redis2;
69 |
70 | private NedisClient client1;
71 |
72 | private NedisClient client2;
73 |
74 | private RoundRobinNedisClientPool clientPool;
75 |
76 | private NedisClient client;
77 |
78 | private String zkPath = "/" + getClass().getName();
79 |
80 | private void deleteDirectory(File directory) throws IOException {
81 | if (!directory.exists()) {
82 | return;
83 | }
84 | Files.walkFileTree(directory.toPath(), new SimpleFileVisitor() {
85 |
86 | @Override
87 | public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
88 | throws IOException {
89 | Files.delete(file);
90 | return FileVisitResult.CONTINUE;
91 | }
92 |
93 | @Override
94 | public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
95 | Files.delete(dir);
96 | return FileVisitResult.CONTINUE;
97 | }
98 |
99 | });
100 | }
101 |
102 | private void addNode(String name, int port, String state) throws IOException,
103 | InterruptedException, KeeperException {
104 | ZooKeeper zk = new ZooKeeper("localhost:" + zkPort, 5000, null);
105 | try {
106 | if (zk.exists(zkPath, null) == null) {
107 | zk.create(zkPath, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
108 | }
109 | ObjectNode node = mapper.createObjectNode();
110 | node.put("addr", "127.0.0.1:" + port);
111 | node.put("state", state);
112 | zk.create(zkPath + "/" + name, mapper.writer().writeValueAsBytes(node),
113 | ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
114 | } finally {
115 | zk.close();
116 | }
117 | }
118 |
119 | private void removeNode(String name) throws InterruptedException, KeeperException, IOException {
120 | ZooKeeper zk = new ZooKeeper("localhost:" + zkPort, 5000, null);
121 | try {
122 | zk.delete(zkPath + "/" + name, -1);
123 | } finally {
124 | zk.close();
125 | }
126 | }
127 |
128 | private void waitUntilZkUp(int port) throws InterruptedException {
129 | for (;;) {
130 | ZooKeeper zk = null;
131 | try {
132 | zk = new ZooKeeper("127.0.0.1:" + port, 5000, null);
133 | zk.getChildren("/", null);
134 | return;
135 | } catch (Exception e) {
136 | Thread.sleep(200);
137 | } finally {
138 | if (zk != null) {
139 | zk.close();
140 | }
141 | }
142 | }
143 | }
144 |
145 | @Before
146 | public void setUp() throws Exception {
147 | deleteDirectory(testDir);
148 | testDir.mkdirs();
149 |
150 | zkPort = probeFreePort();
151 | zkServer = new ZooKeeperServerWapper(zkPort, testDir);
152 | zkServer.start();
153 | waitUntilZkUp(zkPort);
154 |
155 | redisPort1 = probeFreePort();
156 | redis1 = new RedisServer(redisPort1);
157 | redis1.start();
158 | waitUntilRedisUp(redisPort1);
159 |
160 | redisPort2 = probeFreePort();
161 | redis2 = new RedisServer(redisPort2);
162 | redis2.start();
163 | waitUntilRedisUp(redisPort2);
164 |
165 | NedisClientPoolBuilder poolBuilder = NedisClientPoolBuilder.create();
166 |
167 | client1 = NedisUtils.newPooledClient(poolBuilder.remoteAddress("localhost", redisPort1)
168 | .build());
169 | client2 = NedisUtils.newPooledClient(poolBuilder.remoteAddress("localhost", redisPort2)
170 | .build());
171 |
172 | addNode("node1", redisPort1, "online");
173 | clientPool = RoundRobinNedisClientPool.builder().poolBuilder(poolBuilder)
174 | .curatorClient("localhost:" + zkPort, 30000).zkProxyDir(zkPath).build().sync()
175 | .getNow();
176 | client = NedisUtils.newPooledClient(clientPool);
177 | }
178 |
179 | @After
180 | public void tearDown() throws IOException, InterruptedException {
181 | client.close().sync();
182 | client1.close().sync();
183 | client2.close().sync();
184 | if (redis1 != null) {
185 | redis1.stop();
186 | }
187 | if (redis2 != null) {
188 | redis2.stop();
189 | }
190 | if (zkServer != null) {
191 | zkServer.stop();
192 | }
193 | deleteDirectory(testDir);
194 | }
195 |
196 | @Test
197 | public void test() throws IOException, InterruptedException, KeeperException {
198 | assertTrue(client.set(toBytes("k1"), toBytes("v1")).sync().getNow().booleanValue());
199 | assertEquals("v1", bytesToString(client1.get(toBytes("k1")).sync().getNow()));
200 | // fake node
201 | addNode("node2", 12345, "offline");
202 | Thread.sleep(3000);
203 | assertTrue(client.set(toBytes("k2"), toBytes("v2")).sync().getNow().booleanValue());
204 | assertEquals("v2", bytesToString(client1.get(toBytes("k2")).sync().getNow()));
205 |
206 | addNode("node3", redisPort2, "online");
207 | Thread.sleep(3000);
208 | assertTrue(client.set(toBytes("k3"), toBytes("v3")).sync().getNow().booleanValue());
209 | assertEquals("v3", bytesToString(client2.get(toBytes("k3")).sync().getNow()));
210 |
211 | removeNode("node1");
212 | Thread.sleep(3000);
213 | assertTrue(client.set(toBytes("k4"), toBytes("v4")).sync().getNow().booleanValue());
214 | assertEquals("v4", bytesToString(client2.get(toBytes("k4")).sync().getNow()));
215 |
216 | System.out.println(clientPool.numConns());
217 | System.out.println(clientPool.numPooledConns());
218 | }
219 | }
220 |
--------------------------------------------------------------------------------
/codis-client/src/test/java/io/codis/nedis/codis/ZooKeeperServerWapper.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 CodisLabs.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.codis.nedis.codis;
17 |
18 | import java.io.File;
19 | import java.io.IOException;
20 |
21 | import org.apache.zookeeper.server.ServerCnxnFactory;
22 | import org.apache.zookeeper.server.ZooKeeperServer;
23 | import org.apache.zookeeper.server.persistence.FileTxnSnapLog;
24 |
25 | /**
26 | * @author Apache9
27 | */
28 | public class ZooKeeperServerWapper {
29 |
30 | private volatile ServerCnxnFactory cnxnFactory;
31 |
32 | private volatile ZooKeeperServer zkServer;
33 |
34 | private volatile FileTxnSnapLog ftxn;
35 |
36 | private int port;
37 |
38 | private File baseDir;
39 |
40 | public ZooKeeperServerWapper(int port, File baseDir) throws Exception {
41 | this.port = port;
42 | this.baseDir = baseDir;
43 | }
44 |
45 | public void start() throws IOException, InterruptedException {
46 | ZooKeeperServer zkServer = new ZooKeeperServer();
47 | FileTxnSnapLog ftxn = new FileTxnSnapLog(
48 | new File(baseDir, "zookeeper"), new File(baseDir, "zookeeper"));
49 | zkServer.setTxnLogFactory(ftxn);
50 | zkServer.setTickTime(1000);
51 | ServerCnxnFactory cnxnFactory = ServerCnxnFactory.createFactory(port,
52 | 100);
53 | cnxnFactory.startup(zkServer);
54 | this.cnxnFactory = cnxnFactory;
55 | this.zkServer = zkServer;
56 | this.ftxn = ftxn;
57 | }
58 |
59 | public void stop() throws IOException {
60 | cnxnFactory.shutdown();
61 | ftxn.close();
62 | }
63 |
64 | public boolean isRunning() {
65 | if (zkServer == null) {
66 | return false;
67 | } else {
68 | return zkServer.isRunning();
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/jedis-LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2010 Jonathan Leibiusky
2 |
3 | Permission is hereby granted, free of charge, to any person
4 | obtaining a copy of this software and associated documentation
5 | files (the "Software"), to deal in the Software without
6 | restriction, including without limitation the rights to use,
7 | copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the
9 | Software is furnished to do so, subject to the following
10 | conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/nedis-bench/assembly/assembly.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | tar.gz
5 | dir
6 |
7 | asm
8 | true
9 |
10 |
11 | assembly/bin
12 | bin
13 | 0755
14 | true
15 |
16 |
17 |
18 |
19 | lib
20 | runtime
21 |
22 |
23 |
--------------------------------------------------------------------------------
/nedis-bench/assembly/bin/bench.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | JAVA_OPTS="-Xmx1g -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=65 -XX:+CMSParallelRemarkEnabled"
4 | JAVA=$JAVA_HOME/bin/java
5 |
6 | function usage() {
7 | echo "Usage: bash $0 nedis|jedis command"
8 | echo "command:"
9 | echo " start"
10 | echo " stop"
11 | exit 1
12 | }
13 |
14 | if [ $# -lt 2 ]; then
15 | usage
16 | fi
17 |
18 | if [ "$1" == nedis ]; then
19 | MAINCLASS="io.codis.nedis.bench.NedisBench"
20 | OUT_FILE=nedis.out.$(date +%y%m%d-%H%M%S)
21 | else
22 | MAINCLASS="io.codis.nedis.bench.JedisBench"
23 | OUT_FILE=jedis.out.$(date +%y%m%d-%H%M%S)
24 | fi
25 |
26 | COMMAND=$2
27 | shift 2
28 |
29 | if [ ${COMMAND} == "start" ];then
30 | # add libs to CLASSPATH
31 | for f in lib/*.jar; do
32 | CLASSPATH=${CLASSPATH}:$f;
33 | done
34 | export CLASSPATH
35 | nohup ${JAVA} ${JAVA_OPTS} ${MAINCLASS} &>${OUT_FILE} $@ &
36 | sleep 3
37 | echo
38 | # show some logs by tail
39 | tail -n 10 ${OUT_FILE}
40 | fi
41 |
42 | if [ ${COMMAND} == "stop" ];then
43 | PIDS=`ps x | grep ${MAINCLASS} | grep -v grep | grep java | awk '{print $1}'`
44 | for PID in ${PIDS};do
45 | kill -9 ${PID}
46 | echo "kill process from pid: ${PID}"
47 | done
48 | fi
49 |
--------------------------------------------------------------------------------
/nedis-bench/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | nedis
6 | io.codis.nedis
7 | 0.2.0-SNAPSHOT
8 |
9 | io.codis.nedis
10 | nedis-bench
11 | 0.2.0-SNAPSHOT
12 | jar
13 |
14 | UTF-8
15 | 1.7
16 | UTF-8
17 | UTF-8
18 | UTF-8
19 | UTF-8
20 |
21 |
22 |
23 | io.codis.nedis
24 | nedis-client
25 |
26 |
27 | com.google.guava
28 | guava
29 |
30 |
31 | redis.clients
32 | jedis
33 | 2.7.3
34 |
35 |
36 | args4j
37 | args4j
38 | 2.32
39 |
40 |
41 |
42 |
43 |
44 | org.apache.maven.plugins
45 | maven-deploy-plugin
46 | 2.8.2
47 |
48 | true
49 |
50 |
51 |
52 | org.apache.maven.plugins
53 | maven-assembly-plugin
54 | 2.4
55 |
56 | ${project.artifactId}
57 | false
58 |
59 | assembly/assembly.xml
60 |
61 |
62 |
63 |
64 | package
65 |
66 | single
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/nedis-bench/src/main/java/io/codis/nedis/bench/JedisBench.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 CodisLabs.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.codis.nedis.bench;
17 |
18 | import java.util.concurrent.ExecutorService;
19 | import java.util.concurrent.Executors;
20 | import java.util.concurrent.ThreadLocalRandom;
21 | import java.util.concurrent.TimeUnit;
22 | import java.util.concurrent.atomic.AtomicBoolean;
23 | import java.util.concurrent.atomic.AtomicLong;
24 |
25 | import org.kohsuke.args4j.CmdLineException;
26 | import org.kohsuke.args4j.CmdLineParser;
27 | import org.kohsuke.args4j.Option;
28 |
29 | import redis.clients.jedis.Jedis;
30 | import redis.clients.jedis.JedisPool;
31 | import redis.clients.jedis.JedisPoolConfig;
32 | import redis.clients.jedis.Pipeline;
33 |
34 | import com.google.common.net.HostAndPort;
35 | import com.google.common.util.concurrent.ThreadFactoryBuilder;
36 |
37 | /**
38 | * @author Apache9
39 | */
40 | public class JedisBench {
41 |
42 | private static class Args {
43 |
44 | @Option(name = "-c", required = true)
45 | public int conns;
46 |
47 | @Option(name = "-pl")
48 | public int pipeline;
49 |
50 | @Option(name = "-t", required = true)
51 | public int threads;
52 |
53 | @Option(name = "-m")
54 | public long minutes = TimeUnit.DAYS.toMinutes(1);
55 |
56 | @Option(name = "-r", required = true)
57 | public String redisAddr;
58 | }
59 |
60 | private static final class Worker implements Runnable {
61 |
62 | private final AtomicBoolean stop;
63 |
64 | private final AtomicLong reqCount;
65 |
66 | private final JedisPool pool;
67 |
68 | private final int pipeline;
69 |
70 | public Worker(AtomicBoolean stop, AtomicLong reqCount, JedisPool pool, int pipeline) {
71 | this.stop = stop;
72 | this.reqCount = reqCount;
73 | this.pool = pool;
74 | this.pipeline = pipeline;
75 | }
76 |
77 | private void testPipeline(byte[] key, byte[] value) {
78 | while (!stop.get()) {
79 | try (Jedis jedis = pool.getResource()) {
80 | Pipeline p = jedis.pipelined();
81 | for (int i = 0; i < pipeline / 2; i++) {
82 | p.set(key, value);
83 | p.get(key);
84 | }
85 | p.sync();
86 | reqCount.addAndGet(pipeline);
87 | }
88 | }
89 | }
90 |
91 | private void testNormal(byte[] key, byte[] value) {
92 | while (!stop.get()) {
93 | try {
94 | try (Jedis jedis = pool.getResource()) {
95 | jedis.set(key, value);
96 | }
97 | reqCount.incrementAndGet();
98 | try (Jedis jedis = pool.getResource()) {
99 | jedis.get(key);
100 | }
101 | reqCount.incrementAndGet();
102 | } catch (Throwable t) {
103 | t.printStackTrace();
104 | System.exit(1);
105 | }
106 | }
107 | }
108 |
109 | @Override
110 | public void run() {
111 | byte[] key = new byte[4];
112 | byte[] value = new byte[16];
113 | ThreadLocalRandom.current().nextBytes(key);
114 | ThreadLocalRandom.current().nextBytes(value);
115 | if (pipeline > 0) {
116 | testPipeline(key, value);
117 | } else {
118 | testNormal(key, value);
119 | }
120 | }
121 | }
122 |
123 | public static void main(String[] args) throws InterruptedException {
124 | Args parsedArgs = new Args();
125 | CmdLineParser parser = new CmdLineParser(parsedArgs);
126 | try {
127 | parser.parseArgument(args);
128 | } catch (CmdLineException e) {
129 | parser.printUsage(System.err);
130 | return;
131 | }
132 |
133 | AtomicBoolean stop = new AtomicBoolean(false);
134 | AtomicLong reqCount = new AtomicLong(0);
135 | ExecutorService executor = Executors.newFixedThreadPool(parsedArgs.threads,
136 | new ThreadFactoryBuilder().setDaemon(true).build());
137 | HostAndPort hap = HostAndPort.fromString(parsedArgs.redisAddr);
138 | JedisPoolConfig config = new JedisPoolConfig();
139 | config.setMaxTotal(parsedArgs.conns);
140 | config.setMaxIdle(parsedArgs.conns);
141 | JedisPool pool = new JedisPool(config, hap.getHostText(), hap.getPort());
142 | for (int i = 0; i < parsedArgs.threads; i++) {
143 | executor.execute(new Worker(stop, reqCount, pool, parsedArgs.pipeline));
144 | }
145 | long duration = TimeUnit.MINUTES.toNanos(parsedArgs.minutes);
146 | long startTime = System.nanoTime();
147 | long prevTime = -1L;
148 | long prevReqCount = -1L;
149 | for (;;) {
150 | long currentTime = System.nanoTime();
151 | if (currentTime - startTime >= duration) {
152 | stop.set(true);
153 | executor.shutdown();
154 | if (!executor.awaitTermination(1, TimeUnit.MINUTES)) {
155 | throw new RuntimeException("Can not terminate workers");
156 | }
157 | System.out.println(String.format("Test run %d minutes, qps: %.2f",
158 | parsedArgs.minutes, (double) reqCount.get() / (currentTime - startTime)
159 | * TimeUnit.SECONDS.toNanos(1)));
160 | pool.close();
161 | return;
162 | }
163 | long currentReqCount = reqCount.get();
164 | if (prevTime > 0) {
165 | System.out.println(String.format("qps: %.2f",
166 | (double) (currentReqCount - prevReqCount) / (currentTime - prevTime)
167 | * TimeUnit.SECONDS.toNanos(1)));
168 | }
169 | prevTime = currentTime;
170 | prevReqCount = currentReqCount;
171 | Thread.sleep(5000);
172 | }
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/nedis-bench/src/main/java/io/codis/nedis/bench/NedisBench.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015 CodisLabs.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.codis.nedis.bench;
17 |
18 | import io.codis.nedis.NedisClient;
19 | import io.codis.nedis.NedisClientPoolBuilder;
20 | import io.codis.nedis.util.NedisUtils;
21 | import io.netty.util.concurrent.Future;
22 | import io.netty.util.concurrent.FutureListener;
23 |
24 | import java.util.concurrent.ExecutorService;
25 | import java.util.concurrent.Executors;
26 | import java.util.concurrent.Semaphore;
27 | import java.util.concurrent.ThreadLocalRandom;
28 | import java.util.concurrent.TimeUnit;
29 | import java.util.concurrent.atomic.AtomicBoolean;
30 | import java.util.concurrent.atomic.AtomicLong;
31 |
32 | import org.kohsuke.args4j.CmdLineException;
33 | import org.kohsuke.args4j.CmdLineParser;
34 | import org.kohsuke.args4j.Option;
35 |
36 | import com.google.common.net.HostAndPort;
37 | import com.google.common.util.concurrent.ThreadFactoryBuilder;
38 |
39 | /**
40 | * @author Apache9
41 | */
42 | public class NedisBench {
43 |
44 | private static class Args {
45 |
46 | @Option(name = "-c", required = true)
47 | public int conns;
48 |
49 | @Option(name = "-pl")
50 | public int pipeline;
51 |
52 | @Option(name = "-t", required = true)
53 | public int threads;
54 |
55 | @Option(name = "-m")
56 | public long minutes = TimeUnit.DAYS.toMinutes(1);
57 |
58 | @Option(name = "-r", required = true)
59 | public String redisAddr;
60 | }
61 |
62 | private static final class Worker implements Runnable {
63 |
64 | private final AtomicBoolean stop;
65 |
66 | private final AtomicLong reqCount;
67 |
68 | private final NedisClient client;
69 |
70 | private final int pipeline;
71 |
72 | public Worker(AtomicBoolean stop, AtomicLong reqCount, NedisClient client, int pipeline) {
73 | this.stop = stop;
74 | this.reqCount = reqCount;
75 | this.client = client;
76 | this.pipeline = pipeline;
77 | }
78 |
79 | private void testAsync(byte[] key, byte[] value) {
80 | final Semaphore concurrencyControl = new Semaphore(pipeline);
81 | FutureListener