Nothing substantial from me, just thanks for a very informative post.
So you'd suggest happstack provide a limited sort of memcached built in ? Seems like a good idea to me.
> I haven't read the original post yet, but I've also been thinking it
> would be a good idea to provide some automatic file caching.
I'm going to chime in to respectfully disagree.
Any file that is served this often will be sitting in the Linux buffer
cache. I'll bet dollars-to-donuts that the reason for the 2x performance
penalty is the kernel -> userland -> kernel data copy that fileServe
does, and the extra context switch that comes with it.
If we could figure out how to teach happstack to use sendfile(), the
issue would be moot.
G
--
Gregory Collins <gr...@gregorycollins.net>
> Hi
>
> So, people who use template html in Happstack, might still consider
> reading the templates into memory at start up.
Hi,
That's exactly the way HStringTemplate works by default.
G.
--
Gregory Collins <gr...@gregorycollins.net>
> Nice. I hadn't looked into HStringTemplate at all.
>
> About sendFile, which seems to be the optimal solution for static
> files. It doesn't seem to me that there is a way to implement it in
> fileServe. It is simpleHTTP that would need to be rewritten to accept
> a sendFile system call instead of a bytestring as the response body.
> That would change the whole type system of Happstack. Or am I wrong?
No, that's exactly right. I've been percolating on this a while, there
are a couple of ways it could go:
* Change ServerPartT/WebT. The output type of WebT would change; instead
of "Maybe (Either Response a, FilterFun Response)" (where "a" will
eventually get a "ToMessage" class constraint), you'd change it do
something like this:
data WebTResponse a = DontHandle
| ShortCircuit (Response, FilterFun Response)
| Finished (a, FilterFun Response)
| HandledViaRawSocket Bool
(Obviously we probably wouldn't export these constructors.)
"HandledViaRawSocket" would be returned if the programmer decided to
use raw I/O; the burden of properly following the HTTP protocol was
would be left to the programmer (although we'd provide useful helper
functions). The argument to "HandledViaRawSocket" would indicate
keepalive status. I imagine that you'd call a function like this:
withRawSocket :: MonadIO m => (Request -> Socket -> IO Bool)
-> ServerPartT m ()
The downside to this is that all of the guts would have to change, but
if you were careful you might get away with not having to change any
client code.
* Create an alternative to simpleHTTP' that would accept ServerPartTs as
they exist now, and also another type of raw handler:
newtype RawServerPartT m a = RawServerPartT {
unRawServerPartT :: ReaderT Request (RawWebT m) a
}
newtype RawWebT m a = RawWebT {
unRawWebT :: ErrorT (Socket -> m Bool) m a
}
I'm not very satisfied with this, but maybe you get the idea; if you
call "withRawSocket" then subsequent monad processing ceases and it'll
run your IO action. (i.e. you don't get to grab the socket unless
you're going to commit to handling the request.) Otherwise, we ignore
the result and treat it as a refusal to handle the request. The driver
function would look something like this:
complicatedHTTP' :: (Monad m, ToMessage b) =>
Conf
-> (m Bool -> IO Bool)
-> RawServerPartT m c
( m (Maybe (Either Response a, FilterFun Response))
-> IO (Maybe (Either Response b, FilterFun Response)))
-> ServerPartT m a
-> IO ()
The other solution is a little more consistent but this one has the
advantage that it doesn't disturb any of the other code.
My primary concern was that the caching be transparent, and a sendfile
solution certainly qualifies. My wording didn't indicate that because
I had only given the problem cursory thought and had not considered
the OS-level solution. I don't have a problem with leaving non-*nix
OS's out here, since that's not an obstacle for me.