about summary refs log tree commit homepage
DateCommit message (Collapse)
2019-06-24ds: split out IO::KQueue-specific code
We don't need to code multiple event loops or have branches in watch() if we can easily make the IO::KQueue-based interface look like our lower-level epoll_* API.
2019-06-24daemon: use FreeBSD accept filters on non-NNTP
Similar to TCP_DEFER_ACCEPT on Linux, FreeBSD has a 'dataready' accept filter which we can use to reduce wakeups when doing TLS negotiation or plain HTTP. There's also a 'httpready' which we can use for plain HTTP connections.
2019-06-24daemon: set TCP_DEFER_ACCEPT on everything but NNTP
This Linux-specific option can save us some wakeups during the TLS negotiation phase, and it can help with ordinary HTTP, too. Plain NNTP (and in the future, POP3) are the only things which require the server send messages, first.
2019-06-24nntp: send greeting immediately for plain sockets
A tiny write() for the greeting on a just accept()-ed TCP socket won't fail with EAGAIN, so we can avoid the extra epoll syscall traffic with plain sockets.
2019-06-24ci: require IO::KQueue on FreeBSD, for now
We'll likely replace IO::KQueue (at least on FreeBSD) using a pure-Perl syscall()-based version since syscall numbers are consistent across architectures on FreeBSD and easy to maintain. IO::KQueue->EV_SET is also shockingly inefficient in that it calls kqueue() as much as epoll_ctl.
2019-06-24nntp: lazily allocate and stash rbuf
Allocating a per-client buffer up front is unnecessary and wastes a hash slot. For the majority of (non-malicious) clients, we won't need to store rbuf in a long-lived object associated with a client socket at all. This saves around 10M on 64-bit with 20K connected-but-idle clients.
2019-06-24ds: flush_write runs ->write callbacks even if closed
We may need to rely on cleanup code running in enqueued callbacks, so ensure we call it when flush_write happens.
2019-06-24nntp: simplify long response logic and fix nesting
We can get rid of the {long_res} field and reuse the write buffer ordering logic to prevent nesting of responses from requeue. On FreeBSD, this fixes a problem of callbacks firing twice because kqueue as event_step is now our only callback entry point. There's a slight change in the stdout "logging" format, in that we can no longer distinguish between writes blocked due to slow clients or deferred long responses. Not sure if this affects anybody parsing logs or not, but preserving the old format could prove expensive and not worth the effort.
2019-06-24ds: always use EV_ADD with EV_SET
kqueue EV_ONESHOT semantics are different than epoll EPOLLONESHOT. epoll only disables watches for that event while keeping the item in the rbtree for future EPOLL_CTL_MOD. kqueue removes the watch from the filter set entirely, necessitating the use of EV_ADD for future modifications.
2019-06-24nntp: reduce allocations for greeting
No need to allocate a new PerlIO::scalar filehandle for every client, instead we can now pass the same CODE reference which calls DS->write on a reused string reference.
2019-06-24ds: allow ->write callbacks to syswrite directly
We can bypass buffering when wbuf is empty when it's called from a CODE reference passed to ->write.
2019-06-24daemon: use SSL_MODE_RELEASE_BUFFERS
34K per idle connection adds up to large amounts of memory; especially with the speed of malloc nowadays compared to the cost of cache misses or worse, swapping.
2019-06-24t/nntpd-tls: slow client connection test
We need to ensure slowly negotiating TLS clients don't block the event loop. This is why I added the size check of {wbuf} before and after calling the CODE ref in DS::flush_write.
2019-06-24nntp: call SSL_shutdown in normal cases
This is in accordance with TLS standards and will be needed to support session caching/reuse in the future. However, we don't issue shutdown(2) since we know not to inadvertantly share our sockets with other processes.
2019-06-24ds|nntp: use CORE::close on socket
IO::Socket::SSL will try to re-bless back to the original class on TLS negotiation failure. Unfortunately, the original class is 'GLOB', and re-blessing to 'GLOB' takes away all the IO::Handle methods, because Filehandle/IO are a special case in Perl5. Anyways, since we already use syswrite() and sysread() as functions on our socket, we might as well use CORE::close(), as well (and it plays nicely with tied classes).
2019-06-24daemon: map inherited sockets to well-known schemes
I don't want to specify "--listen" in my systemd .service files, so map 563 to NNTPS automatically (and 443 to HTTPS, but HTTPS support doesn't work, yet).
2019-06-24certs/create-certs.perl: fix cert validity on 32-bit
If I'm still alive, I won't be coding after 2038 :<
2019-06-24nntp: NNTPS and NNTP+STARTTLS working
It kinda, barely works, and I'm most happy I got it working without any modifications to the main NNTP::event_step callback thanks to the DS->write(CODE) support we inherited from Danga::Socket.
2019-06-24nntp: wait for writability before sending greeting
This will be needed for NNTPS support, since we need to negotiate the TLS connection before writing the greeting and we can reuse the existing buffer layer to enqueue writes.
2019-06-24ds: deal better with FS-related errors IO buffers
Instead of ENOMEM (or fragmentation/swap storms), using tempfile buffers opens us up to filesystem and storage-related errors (e.g. ENOSPC, EFBIG, EIO, EROFS). Log these errors, drop the particular client, and try to limp by with whateve we have left.
2019-06-24allow use of PerlIO layers for filesystem writes
It may make sense to use PerlIO::mmap or PerlIO::scalar for DS write buffering with IO::Socket::SSL or similar (since we can't use MSG_MORE), so that means we need to go through buffering in userspace for the common case; while still being easily compatible with slow clients. And it also simplifies GitHTTPBackend slightly. Maybe it can make sense for HTTP input buffering, too...
2019-06-24nntp: simplify re-arming/requeue logic
We can be smarter about requeuing clients to run and avoid excessive epoll_ctl calls since we can trust event_step to do the right thing depending on the state of the client.
2019-06-24ds: hoist out do_read from NNTP and HTTP
Both NNTP and HTTP have common needs and we can factor out some common code to make dealing with IO::Socket::SSL easier.
2019-06-24http|nntp: be explicit about bytes::length on rbuf
It should not matter because our rbuf is always from a socket without encoding layers, but this makes things easier to follow.
2019-06-24ds: remove pointless exit calls
They're never called; the only way to break out of that loop is the PostEventLoop callback.
2019-06-24evcleanup: replace _run_asap with `event_step' callback
No point in keeping a one-line wrapper sub around.
2019-06-24ds: pass $self to code references
We can reduce the amount of short-lived anonymous subs we create by passing $self to code references.
2019-06-24http: don't pass extra args to PublicInbox::DS::close
YAGNI Followup-to: commit 30ab5cf82b9d47242640f748a0f9a088ca783e32 ("ds: reduce Errno imports and drop ->close reason")
2019-06-24ds: favor `delete' over assigning fields to `undef'
This is cleaner in most cases and may allow Perl to reuse memory from unused fields. We can do this now that we no longer support Perl 5.8; since Danga::Socket was written with struct-like pseudo-hash support in mind, and Perl 5.9+ dropped support for pseudo-hashes over a decade ago.
2019-06-24http|nntp: favor "$! == EFOO" over $!{EFOO} checks
Integer comparisions of "$!" are faster than hash lookups. See commit 6fa2b29fcd0477d126ebb7db7f97b334f74bbcbc ("ds: cleanup Errno imports and favor constant comparisons") for benchmarks.
2019-06-24qspawn: describe where `$rpipe' come from
It wasn't immediately obvious to me after several months of not looking at this code.
2019-06-24spawn: remove `Blocking' flag handling
Instead, the O_NONBLOCK flag is set by PublicInbox::HTTPD::Async; and we won't be setting it elsewhere.
2019-06-24httpd/async: remove EINTR check
This pipe is always non-blocking when run under public-inbox-httpd and it won't fail with EINTR in that case
2019-06-24ds: get rid of event_watch field
We don't need to keep track of that field since we always know what events we're interested in when using one-shot wakeups.
2019-06-24ds: remove IO::Poll support (for now)
It may be reinstated at a later time if there's interest; but I want to be able to use one-shot notifications for certain events while retaining level-triggered notifications others. OTOH, I intend to fully support kqueue; via IO::KQueue for now, but via syscall() eventually to take advantage of the syscall reduction kevent(2) can provide over (current) epoll APIs.
2019-06-24ds: share watch_chg between watch_read/watch_write
There was much duplicate logic between watch_read and watch_write. Share that logic, and give us room to enable edge-triggered or one-shot notifications in the future.
2019-06-24ds: import IO::KQueue namespace
Make the rest of our IO::KQueue-using code less verbose and closer to the C equivalent.
2019-06-24ds: set event flags directly at initialization
We can avoid the EPOLL_CTL_ADD && EPOLL_CTL_MOD sequence with a single EPOLL_CTL_ADD.
2019-06-24syscall: get rid of unnecessary uname local vars
We don't need to keep information from uname(2) around outside of startup.
2019-06-24syscall: get rid of unused EPOLL* constants
EPOLLRDBAND is used for DECnet; and I'm pretty sure I won't be updating any of our code to work with DECnet. I've never found use for EPOLLHUP or EPOLLERR, either; so disable those for now and add comments for things I might actually use: EPOLLET and EPOLLONESHOT.
2019-06-24ds: get rid of redundant and unnecessary POLL* constants
EPOLL* constants already match their POLL* counterparts and there's no way Linux can ever diverge or change the values of those constants. So we'll favor the EPOLL* ones since we use EPOLLEXCLUSIVE, already. For weird stuff like kqueue, we'd need to keep maintaining the mapping, anyways.
2019-06-24ds: switch write buffering to use a tempfile
Data which can't fit into a generously-sized socket buffer, has no business being stored in heap.
2019-06-24ds: share send(..., MSG_MORE) logic
No sense in having similar Linux-specific functionality in both our NNTP.pm and HTTP.pm
2019-06-24http: favor DS->write(strref) when reasonable
This can avoid large memory copies when strings can't be copy-on-write and saves us the trouble of creating new refs in the code.
2019-06-24ds: remove support for DS->write(undef)
We call ->flush_write directly, now; so we can eliminate a needless check.
2019-06-24ds: don't pass `events' arg to EPOLL_CTL_DEL
There's no point in passing a mask of interesting events when removing an item from the epoll watch set.
2019-06-24ds: lazy-initialize wbuf
We don't need write buffering unless we encounter slow clients requesting large responses. So don't waste a hash slot or (empty) arrayref for it.
2019-06-24ds: split out from ->flush_write and ->write
Get rid of the confusing $need_queue variable and all the associated documentation for it. Instead, make it obvious that we're either skipping the write buffer or flushing the write buffer by splitting the sub in two.
2019-06-24ds: lazy initialize wbuf_off
Since Perl 5.10+, "fields" makes a restricted hash; not a compile-time-defined array (struct) with fixed offsets as it did in Perl <= 5.8. Thus in-use fields cost memory, and since the write buffer offset is rarely needed; stop relying on it.
2019-06-24ds: get rid of on_incomplete_write wrapper
Wrong place to be wrapping this method.