Skip to content

Commit 43ecb40

Browse files
authored
Merge pull request #1159 from the-thing/string-builder-trim
Trimming oversized `Message StringBuilder` to page size
2 parents f871a80 + 1a28fe1 commit 43ecb40

2 files changed

Lines changed: 55 additions & 7 deletions

File tree

quickfixj-base/src/main/java/quickfix/Message.java

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -150,17 +150,14 @@ private Object cloneTo(Message message) {
150150
}
151151

152152
private static final class Context {
153+
154+
private static final int MAX_MESSAGE_BUFFER_SIZE = 4096;
153155
private final BodyLength bodyLength = new BodyLength(100);
154156
private final CheckSum checkSum = new CheckSum("000");
155157
private final StringBuilder stringBuilder = new StringBuilder(1024);
156158
}
157159

158-
private static final ThreadLocal<Context> stringContexts = new ThreadLocal<Context>() {
159-
@Override
160-
protected Context initialValue() {
161-
return new Context();
162-
}
163-
};
160+
private static final ThreadLocal<Context> STRING_CONTEXTS = ThreadLocal.withInitial(Context::new);
164161

165162
/**
166163
* Do not call this method concurrently while modifying the contents of the message.
@@ -173,7 +170,7 @@ protected Context initialValue() {
173170
*/
174171
@Override
175172
public String toString() {
176-
Context context = stringContexts.get();
173+
Context context = STRING_CONTEXTS.get();
177174
if (CharsetSupport.isStringEquivalent()) { // length & checksum can easily be calculated after message is built
178175
header.setField(context.bodyLength);
179176
trailer.setField(context.checkSum);
@@ -192,6 +189,11 @@ public String toString() {
192189
}
193190
return stringBuilder.toString();
194191
} finally {
192+
if (stringBuilder.length() > Context.MAX_MESSAGE_BUFFER_SIZE) {
193+
stringBuilder.setLength(Context.MAX_MESSAGE_BUFFER_SIZE);
194+
stringBuilder.trimToSize();
195+
}
196+
195197
stringBuilder.setLength(0);
196198
}
197199
}
@@ -1018,4 +1020,7 @@ void setGarbled(boolean isGarbled) {
10181020
this.isGarbled = isGarbled;
10191021
}
10201022

1023+
StringBuilder getStringBuilder() {
1024+
return STRING_CONTEXTS.get().stringBuilder;
1025+
}
10211026
}

quickfixj-base/src/test/java/quickfix/MessageTest.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import java.time.ZoneOffset;
1414
import java.util.Calendar;
1515
import java.util.TimeZone;
16+
import java.util.concurrent.CompletableFuture;
17+
import java.util.concurrent.Executors;
1618

1719
import org.junit.Rule;
1820
import org.junit.Test;
@@ -746,4 +748,45 @@ public void testHeaderDataField() throws Exception {
746748
DataDictionaryTest.getDictionary());
747749
assertEquals("ABCD", m.getHeader().getString(SecureData.FIELD));
748750
}
751+
752+
@Test
753+
public void shouldTrimStringBuilder() {
754+
// this test must run in a dedicated thread to avoid interference with other test cases (thread local)
755+
CompletableFuture<?> future = CompletableFuture.runAsync(() -> {
756+
Message message = new Message();
757+
758+
message.setString(131, "123456");
759+
String str = message.toString();
760+
761+
assertEquals(23, str.length());
762+
assertEquals(0, message.getStringBuilder().length());
763+
assertEquals(1024, message.getStringBuilder().capacity());
764+
765+
message.setString(131, createLongString());
766+
str = message.toString();
767+
768+
assertEquals(10020, str.length());
769+
assertEquals(0, message.getStringBuilder().length());
770+
assertEquals(4096, message.getStringBuilder().capacity());
771+
772+
message.setString(131, "123456");
773+
str = message.toString();
774+
775+
assertEquals(23, str.length());
776+
assertEquals(0, message.getStringBuilder().length());
777+
assertEquals(4096, message.getStringBuilder().capacity());
778+
}, Executors.newSingleThreadExecutor());
779+
780+
future.join();
781+
}
782+
783+
private static String createLongString() {
784+
StringBuilder builder = new StringBuilder(10_000);
785+
786+
for (int i = 0; i < 10_000; i++) {
787+
builder.append('a');
788+
}
789+
790+
return builder.toString();
791+
}
749792
}

0 commit comments

Comments
 (0)