Skip to content

DataBufferUtils.CompositeMatcher causes poor performance when one or more matchers does not match #25915

@DanielThomas

Description

@DanielThomas

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:

Screen Shot 2020-10-14 at 3 52 11 pm

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.

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)type: bugA general bug

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions