http://hg.dovecot.org/dovecot-2.2/rev/64c73e6bd397

Today I finally committed the "imap-hibernate" feature that I first started 
developing about a year ago (and had been thinking about for several years 
before that). The main purpose here is to reduce the number of imap processes 
and the amount of memory they use by moving IDLEing connections into 
imap-hibernate processes where they are waiting for something to happen 
(changes to the mailbox or IMAP client to do something). Mailbox changes are 
noticed only if inotify/kqueue is enabled, so without them the hibernation 
feature won't work well.

For now only the IMAP connections that are in IDLE can be hibernated. In theory 
non-IDLEing connections could also be hibernated, but the main problem here is 
that if EXPUNGEs can't be sent at the time the hibernation is over, the current 
code can't handle it. They would require recreating a view that contains such 
expunged messages, which could be possible with some extra work.

Some IMAP extensions aren't supported yet:

 - NOTIFY: This would just need to import/export the NOTIFY state. Also 
hibernation could be done at any time if VANISHED replies could be sent to the 
selected mailbox.
 - SEARCH=CONTEXT: A bit more troublesome extension to support. I'm not sure 
how big the trouble would be. It's rarely used though.
 - COMPRESS: The [de]compression code would need to be moved to login process 
instead of being done in imap-compress plugin. This would be a larger change, 
although it's also useful for various other purposes.

The hibernation can be enabled for now simply by setting imap_hibernate_timeout 
setting to non-zero, which controls how long to wait after client has issued 
IDLE (and nothing happens) until the process hibernates.

Some future work might include:

 - Moving the hibernation all the way to the first Dovecot proxy layer to avoid 
the need for imap-hibernate process at all. (Also moving the COMPRESS handling 
all the way there.)
 - Dynamically adjusting when the client should be hibernated instead of just a 
fixed imap_hibernate_timeout setting. Especially try to avoid such a situation 
where the hibernation is almost always terminated soon after it started. 
Although that probably is unlikely, so maybe not worth the trouble to prevent..
 - Hibernation could be used to control the load of the server. If it's running 
too slow or if there are already too many imap processes, some of the 
connections could be moved to hibernation stage. Or just kept in hibernation 
for a while longer even after the imap process would normally be recreated 
(e.g. wait for several minutes before reporting new emails, or several seconds 
before replying to DONE).
 - The EXPUNGE/VANISHED and FETCH FLAGS replies aren't sent asynchronously, but 
instead fully buffered to the output buffer. This works as long as the list of 
changes after hibernation isn't huge, but otherwise it's wasting a lot of 
memory.
 - Maybe support non-inotify/kqueue change notifications from lib-storage. This 
could be complicated though to do efficiently. Or a simple way would be to just 
send a UDP or UNIX datagram packet on all changes to all the imap-hibernate 
processes and see if anybody cares about those. I'm not sure how efficient that 
would be.

Reply via email to