Skip to content

Commit 5e989d9

Browse files
committed
Merge pull request msgpack#293 from msgpack/issue_292
Avoid to flush an extra buffer when the string isn't too large in Mes…
2 parents fe287ba + 5c80a86 commit 5e989d9

File tree

3 files changed

+56
-0
lines changed

3 files changed

+56
-0
lines changed

msgpack-core/src/main/java/org/msgpack/core/MessagePack.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public static class Config
5050
private final int stringEncoderBufferSize;
5151
private final int stringDecoderBufferSize;
5252
private final int packerBufferSize;
53+
private final int packerSmallStringOptimizationThreshold; // This parameter is subject to change
5354
private final int packerRawDataCopyingThreshold;
5455

5556
public Config(
@@ -61,6 +62,7 @@ public Config(
6162
int stringEncoderBufferSize,
6263
int stringDecoderBufferSize,
6364
int packerBufferSize,
65+
int packerSmallStringOptimizationThreshold,
6466
int packerRawDataCopyingThreshold)
6567
{
6668
checkArgument(packerBufferSize > 0, "packer buffer size must be larger than 0: " + packerBufferSize);
@@ -75,6 +77,7 @@ public Config(
7577
this.stringEncoderBufferSize = stringEncoderBufferSize;
7678
this.stringDecoderBufferSize = stringDecoderBufferSize;
7779
this.packerBufferSize = packerBufferSize;
80+
this.packerSmallStringOptimizationThreshold = packerSmallStringOptimizationThreshold;
7881
this.packerRawDataCopyingThreshold = packerRawDataCopyingThreshold;
7982
}
8083

@@ -133,6 +136,11 @@ public int getPackerBufferSize()
133136
return packerBufferSize;
134137
}
135138

139+
public int getPackerSmallStringOptimizationThreshold()
140+
{
141+
return packerSmallStringOptimizationThreshold;
142+
}
143+
136144
public int getPackerRawDataCopyingThreshold()
137145
{
138146
return packerRawDataCopyingThreshold;
@@ -154,6 +162,7 @@ public static class ConfigBuilder
154162
private int stringEncoderBufferSize = 8192;
155163
private int stringDecoderBufferSize = 8192;
156164
private int packerBufferSize = 8192;
165+
private int packerSmallStringOptimizationThreshold = 512; // This parameter is subject to change
157166
private int packerRawDataCopyingThreshold = 512;
158167

159168
public Config build()
@@ -167,6 +176,7 @@ public Config build()
167176
stringEncoderBufferSize,
168177
stringDecoderBufferSize,
169178
packerBufferSize,
179+
packerSmallStringOptimizationThreshold,
170180
packerRawDataCopyingThreshold
171181
);
172182
}
@@ -219,6 +229,12 @@ public ConfigBuilder packerBufferSize(int size)
219229
return this;
220230
}
221231

232+
public ConfigBuilder packerSmallStringOptimizationThreshold(int threshold)
233+
{
234+
this.packerSmallStringOptimizationThreshold = threshold;
235+
return this;
236+
}
237+
222238
public ConfigBuilder packerRawDataCopyingThreshold(int threshold)
223239
{
224240
this.packerRawDataCopyingThreshold = threshold;

msgpack-core/src/main/java/org/msgpack/core/MessagePacker.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,14 @@ public MessagePacker packDouble(double v)
442442
return this;
443443
}
444444

445+
private void packSmallString(String s)
446+
throws IOException
447+
{
448+
byte[] bytes = s.getBytes(MessagePack.UTF8);
449+
packRawStringHeader(bytes.length);
450+
writePayload(bytes);
451+
}
452+
445453
/**
446454
* Pack the input String in UTF-8 encoding
447455
*
@@ -457,6 +465,12 @@ public MessagePacker packString(String s)
457465
return this;
458466
}
459467

468+
if (s.length() < config.getPackerSmallStringOptimizationThreshold()) {
469+
// Write the length and payload of small string to the buffer so that it avoids an extra flush of buffer
470+
packSmallString(s);
471+
return this;
472+
}
473+
460474
CharBuffer in = CharBuffer.wrap(s);
461475
prepareEncoder();
462476

msgpack-core/src/test/scala/org/msgpack/core/MessagePackerTest.scala

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,32 @@ class MessagePackerTest
235235
up1.hasNext shouldBe false
236236
up1.close
237237
}
238+
239+
"pack a lot of String within expected time" in {
240+
val count = 20000
241+
242+
def measureDuration(outputStream: java.io.OutputStream) = {
243+
val packer = MessagePack.newDefaultPacker(outputStream)
244+
var i = 0
245+
while (i < count) {
246+
packer.packString("0123456789ABCDEF")
247+
i += 1
248+
}
249+
packer.close
250+
}
251+
252+
val t = time("packString into OutputStream", repeat = 10) {
253+
block("byte-array-output-stream") {
254+
measureDuration(new ByteArrayOutputStream())
255+
}
256+
257+
block("file-output-stream") {
258+
val (_, fileOutput) = createTempFileWithOutputStream
259+
measureDuration(fileOutput)
260+
}
261+
}
262+
t("file-output-stream").averageWithoutMinMax shouldBe < (t("byte-array-output-stream").averageWithoutMinMax * 4)
263+
}
238264
}
239265

240266
"compute totalWrittenBytes" in {

0 commit comments

Comments
 (0)