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.