I noticed my CPU pegged for over a minute reading a 675K text resource when subscribing to a flux for a response in a test:
val events = ClientResponse.create(HttpStatus.OK)
.body(eventsBody)
.build()
.bodyToFlow<ServerSentEvent<JsonNode>>()
When I hooked up YourKit all the time was being spent in org.springframework.core.io.buffer.DataBufferUtils.KnuthMorrisPrattMatcher#match:

After stepping in the debugger I noticed the problem - the default delimiter bytes are for DOS line endings and newlines and because DataBufferUtils.CompositeMatcher doesn't hold onto state indicating if a matcher previously failed to find a match, each time the newline delimiter is seen the entire input has to be scanned again.
The StringDecoder is created here:
"scheduling-1@17393" prio=5 tid=0xcd nid=NA runnable
java.lang.Thread.State: RUNNABLE
at org.springframework.core.codec.StringDecoder.<init>(StringDecoder.java:79)
at org.springframework.core.codec.StringDecoder.textPlainOnly(StringDecoder.java:239)
at org.springframework.core.codec.StringDecoder.textPlainOnly(StringDecoder.java:229)
at org.springframework.http.codec.ServerSentEventHttpMessageReader.<init>(ServerSentEventHttpMessageReader.java:58)
at org.springframework.http.codec.support.ClientDefaultCodecsImpl.extendObjectReaders(ClientDefaultCodecsImpl.java:103)
at org.springframework.http.codec.support.BaseDefaultCodecs.getObjectReaders(BaseDefaultCodecs.java:354)
at org.springframework.http.codec.support.BaseCodecConfigurer.getReaders(BaseCodecConfigurer.java:100)
at org.springframework.http.codec.support.DefaultClientCodecConfigurer.getReaders(DefaultClientCodecConfigurer.java:31)
at org.springframework.web.reactive.function.client.DefaultExchangeStrategiesBuilder$DefaultExchangeStrategies.<init>(DefaultExchangeStrategiesBuilder.java:86)
at org.springframework.web.reactive.function.client.DefaultExchangeStrategiesBuilder.build(DefaultExchangeStrategiesBuilder.java:71)
at org.springframework.web.reactive.function.client.DefaultExchangeStrategiesBuilder.<clinit>(DefaultExchangeStrategiesBuilder.java:42)
at org.springframework.web.reactive.function.client.ExchangeStrategies.withDefaults(ExchangeStrategies.java:67)
at org.springframework.web.reactive.function.client.DefaultWebClientBuilder.initExchangeStrategies(DefaultWebClientBuilder.java:287)
at org.springframework.web.reactive.function.client.DefaultWebClientBuilder.build(DefaultWebClientBuilder.java:260)
at org.springframework.web.reactive.function.client.WebClient.create(WebClient.java:150)
I've worked around for now by running the file through unix2dos.
I noticed my CPU pegged for over a minute reading a 675K text resource when subscribing to a flux for a response in a test:
When I hooked up YourKit all the time was being spent in
org.springframework.core.io.buffer.DataBufferUtils.KnuthMorrisPrattMatcher#match:After stepping in the debugger I noticed the problem - the default delimiter bytes are for DOS line endings and newlines and because
DataBufferUtils.CompositeMatcherdoesn't hold onto state indicating if a matcher previously failed to find a match, each time the newline delimiter is seen the entire input has to be scanned again.The
StringDecoderis created here:I've worked around for now by running the file through
unix2dos.