Hello,

I'm interested in building a server that serves templated HTML responses, and in doing so does as little allocation and data movement as possible.

I'm doing the templating with Mustache, which writes its output to a Writer:

https://github.com/spullara/mustache.java/blob/master/compiler/src/main/java/com/github/mustachejava/Mustache.java#L57

First question: am i right in thinking that in Undertow, there is no way for a handler to write directly to the response stream, or at least, that this is not a sensible thing to do? It would involve blocking the handler thread, so it seems like it would be completely missing the point.

So, the thing to do then is to get data from a Writer to a Sender.

Currently, i'm doing this:

StringWriter buffer = new StringWriter();
mustacheTemplate.execute(buffer, scope);
exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/html");
exchange.getResponseSender().send(buffer.toString());

Which works. However, it involves accumulating the response data in a StringWriter, then converting it to a String, then handing it to Undertow, which AIUI will later (in AsyncSenderImpl::send(String, Charset, IoCallback)) convert it to a byte array, then copy the contents of the byte array into however many pooled ByteBuffers are necessary, before finally sending the pooled buffers off to the network.

That involves three complete copies of the data!

Second question: is that correct, or have i missed something?

Now, i see that Sender also has a couple of methods that operate directly on ByteBuffers:

Sender::send(ByteBuffer, IoCallback)
Sender::send(ByteBuffer[], IoCallback)

And, AIUI, if i call either of these, then there will be no more copies on the way out to the network.

Third question: are these methods the ones to use if i want to minimise copies?

If so, i have a pile more questions:

Fourth: does it matter if i call the method which takes a single buffer, and pass a buffer bigger than 16 kB? Will that break things, or lead to seriously degraded performance?

Fifth: should the buffers be wrapped or direct?

Sixth: should i create my own buffers, or obtain them from pool that i can reach with exchange.getConnection().getByteBufferPool()?

Seventh: if i use buffers from the pool, whose responsibility is it to return them to the pool, mine or Undertow's?

If the answers to these questions are, respectively, yes, yes, yes, yes, direct, from the pool, mine, then it looks to me like it would be really useful to have a small shim which sits on the exchange and makes it easy to do all this starting from an OutputStream. Something like:

ResponseSlicer slicer = new ResponseSlicer(exchange);
OutputStream out = slicer.getOutputStream();
// use out
slicer.send();

Or even just:

OutputStream out = new ResponseSlicingOutputStream(exchange);
// use out
out.close();

If that seems sensible, i'm happy to write it and raise a pull request to add it.

Thanks,
tom

--
10 PARTY : GOTO 10

_______________________________________________
Undertow-dev mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/undertow-dev

Reply via email to