Skip to content

Commit 1b62f52

Browse files
committed
Testing new way to parse String commands
1 parent 0161e00 commit 1b62f52

File tree

3 files changed

+207
-2
lines changed

3 files changed

+207
-2
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.infinispan.server.resp;
2+
3+
import io.netty.buffer.ByteBuf;
4+
5+
public class LongProcessorOverride extends Intrinsics.Resp2LongProcessor {
6+
static LongProcessorOverride INSTANCE = new LongProcessorOverride();
7+
8+
private LongProcessorOverride() {
9+
complete = true;
10+
// Always 0 until later?
11+
bytesRead = 0;
12+
}
13+
@Override
14+
public long getValue(ByteBuf buffer) {
15+
return buffer.readableBytes() - 4;
16+
}
17+
18+
}

resp-decoder/src/main/java/org/infinispan/server/resp/MyBenchmark.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@
3333

3434
import java.util.Queue;
3535

36-
import org.infinispan.server.resp.GetSetState;
37-
import org.infinispan.server.resp.PipelineState;
3836
import org.openjdk.jmh.annotations.Benchmark;
3937
import org.openjdk.jmh.annotations.Fork;
4038
import org.openjdk.jmh.annotations.Warmup;
@@ -113,4 +111,26 @@ public void testSetPipelinePerf(PipelineState state) {
113111
throw new AssertionError("Set should have returned " + 5 * state.messageCount + " bytes, but was " + writtenAmount);
114112
}
115113
}
114+
115+
@Benchmark
116+
public int testSimpleStringNameParsing(NameState nameState) {
117+
ByteBuf buf = nameState.nextRequest().duplicate();
118+
buf.readerIndex(buf.readerIndex() + 2);
119+
String name = Intrinsics.simpleString(buf);
120+
return NameState.Names.handleString(name);
121+
}
122+
123+
@Benchmark
124+
public int testStringNameParsing(NameState nameState) {
125+
ByteBuf buf = nameState.nextRequest().duplicate();
126+
String name = Intrinsics.bulkString(buf, LongProcessorOverride.INSTANCE);
127+
return NameState.Names.handleString(name);
128+
}
129+
130+
@Benchmark
131+
public int testNewNameParsing(NameState nameState) {
132+
ByteBuf buf = nameState.nextRequest().duplicate();
133+
buf.readerIndex(buf.readerIndex() + 2);
134+
return NameState.Names.handleByteBuf(buf);
135+
}
116136
}
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
package org.infinispan.server.resp;
2+
3+
import java.nio.charset.StandardCharsets;
4+
import java.util.Random;
5+
6+
import org.openjdk.jmh.annotations.Scope;
7+
import org.openjdk.jmh.annotations.Setup;
8+
import org.openjdk.jmh.annotations.State;
9+
10+
import io.netty.buffer.ByteBuf;
11+
import io.netty.buffer.Unpooled;
12+
import io.netty.util.CharsetUtil;
13+
14+
@State(Scope.Benchmark)
15+
public class NameState {
16+
17+
int offset = 0;
18+
ByteBuf[] requests;
19+
20+
@Setup
21+
public void initializeState() {
22+
Names[] possible = Names.values();
23+
requests = new ByteBuf[possible.length];
24+
Random random = new Random(873821);
25+
for (int i = 0; i < requests.length; ++i) {
26+
Names argument = possible[random.nextInt(possible.length)];
27+
String argumentString = argument.name();
28+
requests[i] = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer("\r\n" + argumentString + "\r\n", CharsetUtil.US_ASCII));
29+
}
30+
31+
}
32+
33+
ByteBuf nextRequest() {
34+
if (offset >= requests.length) {
35+
offset = 0;
36+
}
37+
return requests[offset++];
38+
}
39+
40+
public enum Names {
41+
GET(1),
42+
SET(2),
43+
MSET(3),
44+
MGET(4),
45+
INCR(5),
46+
DECR(6),
47+
DEL(7),
48+
CONFIG(8),
49+
PING(9),
50+
PUBLISH(10),
51+
SUBSCRIBE(11),
52+
RESET(12),
53+
READWRITE(13),
54+
READONLY(14),
55+
COMMAND(15),
56+
ECHO(16),
57+
HELLO(17),
58+
AUTH(18),
59+
QUIT(19);
60+
61+
private static final Names[][] indexedNames;
62+
63+
static {
64+
indexedNames = new Names[26][];
65+
// Just manual for now
66+
indexedNames[0] = new Names[] { AUTH };
67+
indexedNames[2] = new Names[] { CONFIG, COMMAND };
68+
indexedNames[3] = new Names[] { DECR, DEL };
69+
indexedNames[4] = new Names[] { ECHO };
70+
indexedNames[6] = new Names[] { GET };
71+
indexedNames[7] = new Names[] { HELLO };
72+
indexedNames[8] = new Names[] { INCR };
73+
indexedNames[12] = new Names[] { MGET, MSET };
74+
indexedNames[15] = new Names[] { PING, PUBLISH };
75+
indexedNames[16] = new Names[] { QUIT };
76+
indexedNames[17] = new Names[] { RESET, READWRITE, READONLY };
77+
indexedNames[18] = new Names[] { SET, SUBSCRIBE };
78+
}
79+
80+
private final int value;
81+
private final byte[] bytes;
82+
83+
Names(int value) {
84+
this.bytes = name().getBytes(StandardCharsets.US_ASCII);
85+
this.value = value;
86+
}
87+
88+
public static int handleByteBuf(ByteBuf buf) {
89+
int readOffset = buf.readerIndex();
90+
byte b = buf.getByte(readOffset);
91+
byte ignoreCase = b >= 97 ? (byte) (b - 97) : (byte) (b - 65);
92+
if (ignoreCase < 0 || ignoreCase > 25) {
93+
throw new IllegalArgumentException();
94+
}
95+
Names[] target = indexedNames[ignoreCase];
96+
if (target == null) {
97+
throw new IllegalArgumentException();
98+
}
99+
for (Names possible : target) {
100+
byte[] possibleBytes = possible.bytes;
101+
// We already read the first char so ensure readable bytes are the same with the /r/n
102+
if (buf.readableBytes() == (possibleBytes.length + 2)) {
103+
boolean matches = true;
104+
for (int i = 1; i < possibleBytes.length; ++i) {
105+
byte upperByte = possibleBytes[i];
106+
byte targetByte = buf.getByte(readOffset + i);
107+
if (upperByte == targetByte || upperByte + 22 == targetByte) {
108+
continue;
109+
}
110+
matches = false;
111+
break;
112+
}
113+
if (matches) {
114+
buf.readerIndex(readOffset + possibleBytes.length + 2);
115+
return possible.value;
116+
}
117+
}
118+
}
119+
throw new IllegalArgumentException();
120+
}
121+
122+
public static int handleString(String name) {
123+
switch (name.toUpperCase()) {
124+
case "GET":
125+
return GET.value;
126+
case "SET":
127+
return SET.value;
128+
case "MSET":
129+
return MSET.value;
130+
case "MGET":
131+
return MGET.value;
132+
case "INCR":
133+
return INCR.value;
134+
case "DECR":
135+
return DECR.value;
136+
case "DEL":
137+
return DEL.value;
138+
case "CONFIG":
139+
return CONFIG.value;
140+
case "PING":
141+
return PING.value;
142+
case "PUBLISH":
143+
return PUBLISH.value;
144+
case "SUBSCRIBE":
145+
return SUBSCRIBE.value;
146+
case "RESET":
147+
return RESET.value;
148+
case "READWRITE":
149+
return READWRITE.value;
150+
case "READONLY":
151+
return READONLY.value;
152+
case "COMMAND":
153+
return COMMAND.value;
154+
case "ECHO":
155+
return ECHO.value;
156+
case "HELLO":
157+
return HELLO.value;
158+
case "AUTH":
159+
return AUTH.value;
160+
case "QUIT":
161+
return QUIT.value;
162+
default:
163+
throw new UnsupportedOperationException("command " + name + " not found!");
164+
}
165+
}
166+
}
167+
}

0 commit comments

Comments
 (0)