From 6fbfd207d5ccb71bd764cc890170f2042305e49e Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Wed, 6 Nov 2013 20:05:36 +0000 Subject: wbuf: document reasoning for the design of these clases The choice to jump directly to temporary files on EAGAIN may seem odd to some, document our reasoning for choosing this approach. --- lib/yahns/wbuf.rb | 24 ++++++++++++++++++++++++ lib/yahns/wbuf_str.rb | 16 +++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/lib/yahns/wbuf.rb b/lib/yahns/wbuf.rb index e6039b7..293019e 100644 --- a/lib/yahns/wbuf.rb +++ b/lib/yahns/wbuf.rb @@ -3,6 +3,30 @@ # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt) require_relative 'wbuf_common' +# This class is triggered whenever we need write buffering for clients +# reading responses slowly. Small responses which fit into kernel socket +# buffers do not trigger this. yahns will always attempt to write to kernel +# socket buffers first to avoid unnecessary copies in userspace. +# +# Thus, most data is into copied to the kernel only once, the kernel +# will perform zero-copy I/O from the page cache to the socket. The +# only time data may be copied twice is the initial write()/send() +# which triggers EAGAIN. +# +# We only buffer to the filesystem (note: likely not a disk, since this +# is short-lived). We let the sysadmin/kernel decide whether or not +# the data needs to hit disk or not. +# +# This avoids large allocations from malloc, potentially limiting +# fragmentation and keeping (common) smaller allocations fast. +# General purpose malloc implementations in the 64-bit era tend to avoid +# releasing memory back to the kernel, so large heap allocations are best +# avoided as the kernel has little chance to reclaim memory used for a +# temporary buffer. +# +# The biggest downside of this approach is it requires an FD, but yahns +# configurations are configured for many FDs anyways, so it's unlikely +# to be a scalability issue. class Yahns::Wbuf # :nodoc: include Yahns::WbufCommon diff --git a/lib/yahns/wbuf_str.rb b/lib/yahns/wbuf_str.rb index 414f3d5..b786a4c 100644 --- a/lib/yahns/wbuf_str.rb +++ b/lib/yahns/wbuf_str.rb @@ -3,12 +3,26 @@ # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt) require_relative 'wbuf_common' +# we only use this for buffering the tiniest responses (which are already +# strings in memory and a handful of bytes). +# +# "HTTP", "/1.1 " +# "HTTP/1.1 100 Continue\r\n\r\n" +# "100 Continue\r\n\r\nHTTP/1.1 " +# +# This is very, very rarely triggered. +# 1) check_client_connection is enabled +# 2) the client sent an "Expect: 100-continue" header +# +# Most output buffering goes through +# the normal Yahns::Wbuf class which uses a temporary file as a buffer +# (suitable for sendfile()) class Yahns::WbufStr # :nodoc: include Yahns::WbufCommon def initialize(str, next_state) @str = str - @next = next_state # :check_client_connection, :http_100_response + @next = next_state # :ccc_done, :r100_done end def wbuf_flush(client) -- cgit v1.2.3-24-ge0c7