Skip to content

Commit 58edd42

Browse files
committed
INTERNAL: Limit bulk get keys size
1 parent c9473d9 commit 58edd42

File tree

2 files changed

+89
-24
lines changed

2 files changed

+89
-24
lines changed

src/main/java/net/spy/memcached/protocol/ascii/AsciiMemcachedNodeImpl.java

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
3131
* Memcached node for the ASCII protocol.
3232
*/
3333
public final class AsciiMemcachedNodeImpl extends TCPMemcachedNodeImpl {
34+
35+
private static final int GET_BULK_CHUNK_SIZE = 200;
36+
3437
public AsciiMemcachedNodeImpl(String name,
3538
SocketAddress sa,
3639
int bufSize, BlockingQueue<Operation> rq,
@@ -42,34 +45,39 @@ public AsciiMemcachedNodeImpl(String name,
4245

4346
@Override
4447
protected void optimize() {
45-
// make sure there are at least two get operations in a row before
46-
// attempting to optimize them.
4748
Operation nxtOp = writeQ.peek();
48-
if (nxtOp instanceof GetOperation && nxtOp.getAPIType() != APIType.MGET) {
49-
optimizedOp = writeQ.remove();
50-
nxtOp = writeQ.peek();
51-
if (nxtOp instanceof GetOperation && nxtOp.getAPIType() != APIType.MGET) {
52-
OptimizedGetImpl og = new OptimizedGetImpl(
53-
(GetOperation) optimizedOp);
54-
optimizedOp = og;
49+
if (!(nxtOp instanceof GetOperation) || nxtOp.getAPIType() == APIType.MGET ||
50+
((GetOperation) nxtOp).getKeys().size() > GET_BULK_CHUNK_SIZE) {
51+
return;
52+
}
5553

56-
do {
57-
GetOperationImpl o = (GetOperationImpl) writeQ.remove();
58-
if (!o.isCancelled()) {
59-
og.addOperation(o);
60-
}
61-
nxtOp = writeQ.peek();
62-
} while (nxtOp instanceof GetOperation &&
63-
nxtOp.getAPIType() != APIType.MGET);
54+
int cnt = ((GetOperation) nxtOp).getKeys().size();
55+
optimizedOp = writeQ.remove();
56+
nxtOp = writeQ.peek();
57+
OptimizedGetImpl og = null;
6458

65-
// Initialize the new mega get
66-
optimizedOp.initialize();
67-
assert optimizedOp.getState() == OperationState.WRITE_QUEUED;
68-
ProxyCallback pcb = (ProxyCallback) og.getCallback();
69-
getLogger().debug("Set up %s with %s keys and %s callbacks",
70-
this, pcb.numKeys(), pcb.numCallbacks());
59+
while (nxtOp instanceof GetOperation && nxtOp.getAPIType() != APIType.MGET) {
60+
if (og == null) {
61+
og = (OptimizedGetImpl) optimizedOp;
62+
assert og != null;
63+
}
64+
cnt += ((GetOperation) nxtOp).getKeys().size();
65+
if (cnt > GET_BULK_CHUNK_SIZE) {
66+
break;
7167
}
68+
GetOperationImpl currentOp = (GetOperationImpl) writeQ.remove();
69+
if (!currentOp.isCancelled()) {
70+
og.addOperation(currentOp);
71+
}
72+
nxtOp = writeQ.peek();
73+
}
74+
// Initialize the new mega get
75+
if (og != null) {
76+
optimizedOp.initialize();
77+
assert optimizedOp.getState() == OperationState.WRITE_QUEUED;
78+
ProxyCallback pcb = (ProxyCallback) optimizedOp.getCallback();
79+
getLogger().debug("Set up %s with %s keys and %s callbacks",
80+
this, pcb.numKeys(), pcb.numCallbacks());
7281
}
7382
}
74-
7583
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package net.spy.memcached;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
import java.util.concurrent.Future;
6+
7+
import org.junit.jupiter.api.Assertions;
8+
import org.junit.jupiter.api.BeforeEach;
9+
import org.junit.jupiter.api.Test;
10+
11+
class OptimizeTest {
12+
13+
private ArcusClientPool client;
14+
private List<String> keys;
15+
16+
@BeforeEach
17+
void setUp() throws Exception {
18+
ConnectionFactoryBuilder builder = new ConnectionFactoryBuilder();
19+
builder.setShouldOptimize(true);
20+
// Get a connection with the get optimization.
21+
client = ArcusClient.createArcusClientPool("127.0.0.1:2181", "test", builder, 1);
22+
23+
keys = new ArrayList<>(10000);
24+
for (int i = 0; i < 100; i++) {
25+
keys.add("k" + i);
26+
Boolean b = client.set(keys.get(i), 0, "value" + i).get();
27+
Assertions.assertEquals(true, b);
28+
}
29+
}
30+
31+
@Test
32+
void testParallelGet() throws Throwable {
33+
List<Future<Object>> results = new ArrayList<>(10000);
34+
for (int i = 0; i < 100; i++) {
35+
results.add(client.asyncGet(keys.get(i)));
36+
}
37+
38+
for (int i = 0; i < 100; i++) {
39+
Object o = results.get(i).get();
40+
Assertions.assertEquals("value" + i, o);
41+
}
42+
}
43+
44+
@Test
45+
void testOptimizedOneOperation() throws Throwable {
46+
List<Future<Object>> results = new ArrayList<>(10000);
47+
for (int i = 0; i < 2; i++) {
48+
results.add(client.asyncGet(keys.get(i)));
49+
}
50+
client.set(keys.get(0), 0, "value0");
51+
52+
for (int i = 0; i < 2; i++) {
53+
Object o = results.get(i).get();
54+
Assertions.assertEquals("value" + i, o);
55+
}
56+
}
57+
}

0 commit comments

Comments
 (0)