Re: [Imap-protocol] Re: Suspend/Restore feature proposal
Michael M Slusarz <[email protected]>
| Newsgroups | gmane.mail.imap.general |
|---|---|
| Message-ID | <20121121183606.Horde.8DDdRoJ261AbQsAiMPfS4w1@bigworm.curecanti.org> |
Quoting Brandon Long <[email protected]>: > On Wed, Nov 21, 2012 at 2:54 PM, Michael M Slusarz > <[email protected]>wrote: > >> Quoting Jan Kundrát <[email protected]>: >> >> Hi Michael, >>> I've read your draft, it's an interesting extension. However, it seems to >>> me that the whole point here is to save a few roundtrips by skipping the >>> process of activating/configuring various optional features. I'll discuss >>> each extension separately. >>> >> >> I would strongly disagree with this statement. As written, the draft is >> only minimally concerned with saving on network round-trips. >> > > Yet, that and bytes are what you quote from your example. That would be a selective reading of my example. I spent the entire previous paragraph before introducing the example stating that other methods of benchmarking would be desirable, but impractical/impossible at this time. I agree that byte counting isn't particularly useful as a benchmark, although it does provide some context (for example: a protocol addition that ADDED net additional bytes on-the-wire would tend to indicate the design/theory is flawed). And I also explicitly indicated the net amount of commands/round-trips/additional IMAP protocol items that were saved, which is a more useful benchmark. >> Sidebar: I'm not a huge fan in general of pipelining as a performance >> since it is not always a feasible option for clients. For example, a >> client may use an OO-library to connect to the IMAP server. This library >> may not provide a reasonable (or any) way of allowing multiple commands to >> be sent at once via the API. For example, to start compression, enable >> QRESYNC, and set the language, it is more than reasonable to expect this >> kind of pseudocode: >> >> $result = $imap->useCompression(true); >> // Check for success >> $imap->useQresync(true); >> // Check for success >> $imap->setLanguage([LANGUAGE])**; >> // Check for success >> >> In any OO IMAP interface the order of IMAP commands to allow for efficient >> pipelining, or the fact that pipelining even exists, should obviously not >> be a part of the API. Thus pipelining is fairly useless in the real world >> as a way to guarantee an increase in performance. >> > Thats not a true statement. Its useless if you're forced to use a bad > client API that you aren't willing to work around? Is that bad client API > going to support adding a new command? How do you suggest writing an IMAP client library API in which the user of the API doesn't need to know ANYTHING about IMAP? Any API that requires the client author to know about pipelining or other IMAP protocol details is worthless. In fact, I'd go so far to say that a useful mail client library API should allow interaction with both an IMAP and POP server using the same commands, albeit with the expectation that some of the more advanced commands - e.g. ACLs - would necessarily need to be null actions when using a POP3 backend. SUSPEND is a general solution and easy to implement (IMHO) and would allow performance gains without understanding the more esoteric details of pipelining. The simple fact that we are discussing which commands would be appropriate for pipelining highlights the latter. >> There are other, more important reasons why a mechanism to restore >> configuration is useful: >> >> - It prevents the need to re-parse the CAPABILITY list. Note that parsing >> the CAPABILITY list involves *MUCH* more than just the actual string >> tokenization of the list, although this alone may not be a trivial task >> (see below). >> >> A client may, depending on the capabilities returned, need to perform >> various internal initialization tasks. For example - if CONDSTORE/QRESYNC >> is listed, a client may have to then parse a separate configuration file to >> grab the details of the local cache where it is storing this information, >> and then connect to this cache, etc. Or if language is listed, a client >> might have to parse a local list of language availability to determine if >> it can/should change the language. >> > > And... it would have had to do that anyways. If its resuming the > connection, it has to either do that initialization or it has to cache that > initialization, both of which it can do just as easily on non-resume if > we're talking about a new connection every 10s. You've proven my point exactly. For you, this kind of initialization may be trivial. For another client, this isn't. You can't make assumptions (incorrectly, in your case) about how a client does work or should work depending on how you do/would do things. > Parse a local list of language availability? So, you want to avoid reading > a local config file ... on the hope that the client doesn't need to know > that language information anyways just to display stuff to the user which > doesn't come from the server? More assumptions about client behavior. I'll agree that my initial example may not be a tremendously useful/practical example, but it is a useful analogy for other initialization tasks that may occur. >> And CAPABILITY parsing is more than just determining what capabilities are >> listed. It is also determining which capabilities SHOULD not be listed. >> Just today, Cyrus was fixed due to a bug that our code was triggering: >> APPENDing binary data via a literal8 caused Cyrus to immediately terminate >> the connection with a BYE response. Our code is smart enough to catch this >> broken behavior by removing BINARY appending from the list of available >> capabilities. But without a way to ensure that every subsequent connection >> is a continuation of the current session, we have to do this detection >> EVERY SINGLE TIME. This is potentially a huge performance hit, since we >> may be appending MBs of data to the server before the BYE response can be >> returned (e.g. appending a sent-mail message containing attachments). >> > > So, you worked around the cyrus bug by determining the connection exhibits > the bug and then never using it for that server again? Or, you could just > not use BINARY ever, or issue an ID command to know if the remote server > has the bug. You could even pipeline it! Or you could store the > known bad server > information somewhere in your app server. * Without a way of determining if the IMAP server we connect to is the same IMAP server we previously connected to when we determined BINARY literal8's were broken, there's nothing we can do except try all over again. You obviously can't assume that the IMAP server is the same. Several of my clients use IMAP load-balancing, and all backend IMAP servers may not be running the same IMAP software/version. * Ack! You didn't just say to use the ID command did you? RFC 2971 [3]: Implementations MUST NOT make operational changes based on the data sent as part of the ID command or response. The ID command is for human consumption only, and is not to be used in improving the performance of clients or servers. This includes, but is not limited to, the following: [...] Clients MUST NOT attempt to work around server bugs based on the ID response. * The Cyrus break apparently only happened recently. Hypothetically: even if using ID information (BAD!), how does that help all of the admins that have installed previous versions of our software where the ID sniff does not catch the issue? * Not use BINARY ever? How do you send null characters? And because *1* version of *1* server is broken, EVERY other server that has ever, or will ever, support BINARY has to be ignored? That's a bummer. * (Getting a bit off topic...) If a server supports BINARY - or at least if it claims to support BINARY - it is a big time win to just send all literals as literal8's. That way you don't have to scan the data stream for nulls, which is potentially an expensive operation when the APPENDed data is 10's of MBs in size (users love sending 10 camera pics in outgoing e-mails for some reason...). So sending literal8's is a significant performance improvement. If a server reports that it supports BINARY, who are we to argue? * For the record, Cyrus is not the only one that has a broken BINARY literal8 implementation (that I know of). For fun, try this on a UW-IMAP BINARY capable server: A1 APPEND INBOX ~{1} A1 BAD Missing literal in APPEND >> - As mentioned above, sending an initialization command to the server may >> take quite a bit of work on the client side to prepare. It's not as easy >> as hardcoding 'ENABLE QRESYNC' in client code - it may take quite a bit of >> CPU cycles to get to that point in a given client. >> > > But this doesn't change anything about the having to do that. Regardless > of whether you're resuming a session or not, you still have to do that work. Back to a client assumption. It is *much* cheaper for us to resume our session than to reinitialize. It may not be true with your implementation but that's irrelevant. >> Another example: a client keeps all of its imap initialization code in a >> separate dynamically-loadable module. If the session is successfully >> resumed, this module does not need to be loaded/interpreted/run. >> > > What kind of clients are we talking about? I'm just completely failing to > think this is an issue. Ours. We keep initialization code in a completely separate class (PHP). That class is never loaded if we don't need to re-initialize (this currently happens when using the current XIMAPPROXY feature discussed in the original thread e-mail). >> - From the server side, it may be much more expensive to initiate an IMAP >> session as compared with resuming one. This draft allows the server to >> optimize if possible. I believe Timo's post indicates that resuming in >> Dovecot is more efficient than creating a new session. >> > > Resuming into the middle of a selected folder seems cheap. Resuming the > status of N commands seems optimizing in the small. I would think it > would cost more in terms of either caching the data in memory or stashing > the data to disk/reading it back than the overhead of parsing a couple > commands and maybe allocating a data structure. I am not a server author so I can't speak to this - one of the reasons I started this thread was to get feedback on just this issue. However, I believe Timo has indicated that it is potentially a performance win (although he is discussing in a slightly different context): http://markmail.org/message/qp45yod5ukqf3jfn >> - Even when pipelining commands, they still need to be sent, the incoming >> command needs to be tokenized (server), the command is performed (server), >> the response sent back, any untagged responses are tokenized (client), the >> untagged responses are interpreted (client), the tagged response is >> tokenized (client), and the tagged response is processed (client). None of >> this is "free". Pipelining eliminates none of this. > > > Tokenization is what clients and servers do, and this takes a trivial > amount of time and cpu in reasonable languages. Yes and no. The higher-level language you get, the less of a chance you get to optimize this. PHP, which I am stuck with, will not be as efficient as C at doing these kind of actions so I can only do so much to improve tokenization speed. I'm not claiming that this is vastly going to improve performance, but you also can't argue that it can't hurt. Not to mention that I have seen many poorly-written tokenizers doing things like using regexps to parse IMAP responses. For these clients, any reduction in the number of commands processed is a much bigger win. So for well-written IMAP clients containing highly tuned tokenizers, I would agree this advantage is of dubious value. But well-written IMAP clients are probably in the minority. >> COMPRESS=DEFLATE > > And what does "resuming" a COMPRESS=DEFLATE do? I assume we're not talking > about trying to keep the old dictionary or anything like that, right? > We're actually talking about just the equivalent of starting it again. I would suggest the proper behavior would be to re-start the compression behavior after the tagged command containing the resume response code. Whether the dictionary should be retained from a previous section would be a decision entirely up to the implementer. > And finally, what IMAP servers support the LANGUAGE extension? >>> >> >> Why does this matter? RFC 5255 is a Standards Track extension. A year >> from now, every IMAP server and 200 new ones may support it. > > > True. But that also goes to my point that you need to specify which > extensions and what information would need to be resumed, you can't just > say "any which apply", what if the server author doesn't think the way you > do and one of these doesn't get resumed? You may have missed this in a previous e-mail response of mine to another commenter: I now agree that this appears to be an unfortunate necessity. I was trying to keep the draft as lean as possible. But discussion of how this command affects current extensions - see, e.g., Section 4 in the draft MOVE extension - is necessary to avoid ambiguities. > But without an actual proof that this is useful for some combination of > client/server, why would we adopt yet another extension that no one will > implement? Whatever I come up with here will be implemented by me in the imapproxy server, whether standardized or not. Timo has indicated an interest to explore the idea further for implementation in Dovecot since he may be implementing something like this internally for other reasons. Obviously our project would implement client side. I would assume the other large PHP-based open source webmail options would be interested. As opposed to some other hella complicated extensions (I'm looking at you CONVERT), this proposal only adds two commands (one is really a simple extension of LOGOUT) and a response code. Thus, this should be something that could be added without having to go in and modify too much existing code (It was an explicit design decision to not add the RESUME information to the authentication command; this would save a round-trip, but add significant complexity and implementation concerns.) > Have you considered not re-establishing a connection every 10s? This is a > connected protocol, not http. From a webmail perspective: if you could tell me how to maintain a consistent IMAP connection using nothing more than current IMAP commands and an out-of-the box HTTP server, I would be ecstatic. That's what users demand our software works with, so that's what we need to code for. I don't have the UI information in front of me right now, but a user initiating an action every 10 seconds, at least when managing messages in a mailbox (loading a message to read, deleting, copying/moving, reporting as spam), seems like a reasonable estimate for discussion purposes. That's where I got the 10 second value from. Thanks again for the additional input and review. michael _______________________________________________ Imap-protocol mailing list [email protected] http://mailman2.u.washington.edu/mailman/listinfo/imap-protocol