[dev] STATUS_SYNC* discussion (Was: [Tickets #11612] Re: Broken imap fetch query)

Michael M Slusarz slusarz at horde.org
Tue Nov 6 04:02:48 UTC 2012


Quoting Michael J Rubinsky <mrubinsk at horde.org>:

> Quoting Michael M Slusarz <slusarz at horde.org>:
>
>> Quoting Michael J Rubinsky <mrubinsk at horde.org>:
>>
>>> Quoting Michael M Slusarz <slusarz at horde.org>:
>
>>> From what you are telling me though, I should be using  
>>> STATUS_UIDNEXT_FORCE for this since the data might not be  
>>> available without the extra server call, correct?
>>
>> Yes - this is a MUST, not a SHOULD.  Or else on certain servers,  
>> you will never see UIDNEXT change - it will always be 0.
>
> Done, thanks for the advice.
>
>> From what it sounds like, you are keeping duplicate cache data  
>> around.  We only need one cache on the server - let the IMP Imap  
>> object do that for you.  Then you just need to carry around the  
>> state of your mailbox as it is known on the activesync device.   
>> This can already be easily done, without IMAP extension querying,  
>> via getCacheId().
>
> When QRESYNC is in use, that's pretty much what I'm doing. I persist  
> the state of the mailbox using MODSEQ, UIDVALIDITY, and UIDNEXT.  
> It's when QRESYNC isn't available that I'm also storing the UIDs and  
> flags.

Why are you storing/comparing flags?  I don't think it's asking too  
much to require someone who wants to use activesync to be using a  
CONDSTORE server, or else they are not getting flag changes.  That's  
the way IMP used to work, and is a reasonable trade-off.

I look at this as analogous to "mailbox" support in POP3.  It would  
definitely be possible to create a system on the Horde/IMP server that  
would allow mailboxes to be abstracted on top of the POP3 model (i.e.  
you keep a local message-id map using SQL storage to indicate which  
messages live in which mailboxes).  But that's really a waste of time  
and re-inventing the wheel since this problem has already been solved  
by IMAP.  Same with flag change tracking.  This issue has been solved  
by CONDSTORE.  Re-inventing a wheel as a way to work around this isn't  
useful when you can just tell an admin to upgrade their IMAP server.

And you should be storing UIDs regardless of whether QRESYNC is  
available.  It can drastically reduce the amount of work necessary to  
resync as seen by the recent VANISHED discussion on the dovecot list.  
At a minimum, keep track of the lowest/highest known UIDs so that you  
can provide a range string to the IMAP commands rather than doing an  
all message command ('1:*').

>> What is missing right now is the ability to take this cache ID  
>> token and give it to Horde_Imap_Client_Base, and have it do all the  
>> necessary things to 1) check the UIDVALIDITY, 2) return the list of  
>> flag changes, and 3) return the list of vanished UIDs.  This is  
>> what I am going to write.  It would do things like automatically  
>> use STATUS_SYNC* if the cache token matched the IMP Imap object  
>> cached state when opening the mailbox for the first time in that  
>> page load.  It would also be able to handle CONDSTORE-only servers,  
>> and be able to do syncing on basic IMAP4rev1 servers.  And this is  
>> all transparent to the calling code.
>>
>> Although I mentioned that getCacheId() already exists, it will not  
>> be used for the new code - it has the design flaw of trying to  
>> allow data access to the string itself (the API documentation for  
>> the return value explains, for example, how to grab the  
>> uidvalidity).  Instead, I am going to implement a getSyncId()  
>> method that returns a string that has no defined format (it's  
>> probably going to be nothing more than a base64 encoded version of  
>> the getCacheId() result).  And then I will implement a  
>> syncMailbox() method that takes the token as its only argument.   
>> This method will throw an exception if the UIDVALIDITY changed,  
>> will return false/null if the mailbox hasn't changed, and will  
>> return four entries if the mailbox has changed:
>>
>>  - flags: Horde_Imap_Client_Ids object of the list of messages  
>> whose flags changed.
>>  - newmsgs: (Boolean) Whether new messages were delivered to the mailbox
>>  - syncid: (String) The new syncid token.
>>  - vanished: Horde_Imap_Client_Ids object of the list of messages  
>> that were expunged.
>>
>> Would this be sufficient for what you need to do in your code?
>
> This sounds great, but I'm still a little fuzzy on how this would  
> work for ActiveSync without ActiveSync controlling the caching.  For  
> example, when not using QRESYNC how would flag changes be determined  
> between any arbitrary state on the ActiveSync client and the current  
> server state?

You can determine flag changes between MODSEQs with CONDSTORE also.

Guess I am confused why you keep saying QRESYNC instead of CONDSTORE.   
For your purposes, everything you can do with QRESYNC you can do with  
CONDSTORE.

The only feature CONDSTORE doesn't provide is an ability to determine  
a list of UIDs that have been deleted since a given modseq.  But so  
what?  You can easily replicate this at the Horde level by determining  
the difference between the list of known UIDs and the current list of  
UIDs in the mailbox (this can now be done for you automatically if you  
call vanished() with the 'ids' parameter).

And you are right: without CONDSTORE you would have to re-sync on  
every sync since there is no way to catch flag changes.  As mentioned  
above, if I was writing the ActiveSync code, I would ignore flag  
changes for non-CONDSTORE servers.

> I need to track more than one different state in case the client  
> reissues the last request. Would the caching be able to still  
> calculate the deltas for an older syncId?

Yes, if using CONDSTORE.  We are just doing IMAP server calls mostly  
(with the one optimization that STATUS_SYNC* cached values are used if  
the initial IMP Imap object mailbox sync happened to be the same  
MODSEQ as the activesync cached data.)

> Currently, the mailbox state is saved to the database, keyed by  
> ActiveSync's syncKey. When not using QRESYNC, each entry is a  
> complete snapshot of the ActiveSync folder state - a list of UIDs on  
> the device along with any flags. There is normally two different  
> versions of this data - the state as it should be if all changes  
> that were just sent were received successfully, and the state of the  
> device *before* the changes were sent.

Are you storing these as "deltas" to each other?  In other words, the  
former should only include the changes to the latter.

> If what you are talking about would be able to handle this  
> transparently, then that would be a complete solution for me,  
> otherwise I will still probably need to track UIDs and flags  
> independently if not using QRESYNC.

Browsed the IMAP code in ActiveSync, and I don't claim to be an  
expert, but these are my thoughts after the above discussion (these  
are my opinions; ymmv):

1.) You need to replace your "QRESYNC" check with a "CONDSTORE" check instead.
2.) Store UIDs (or at least min/max UIDs) for CONDSTORE servers to  
optimize IMAP server commands.
3.) Storing flag state for CONDSTORE servers is not necessary (this  
seems to be what you are doing in  
Horde_ActiveSync_Imap_Adapter#getMessageChanges()).  If a UID is  
indicated as changed, just go ahead and re-sync that particular entry,  
even if it doesn't cause any noticeable change at the activesync UI  
level.  Any gain you might get from the fact that the flag change  
isn't one that you care about, or the flag change was subsequently  
reversed, is offset by the overhead in caching this data.
4.) Ignore all flag changes in non-CONDSTORE servers.

What this means is that for any mailbox, you have the following state entries:

"Before sync" state: IMAP mailbox cached state (UIDNEXT, UIDVALIDITY,  
HIGHESTMODSEQ), list of UIDs on the server
"After sync" state: new IMAP mailbox cached state (UIDNEXT,  
UIDVALIDITY, HIGHESTMODSEQ), list of UIDs sync'd

All FETCH data should be cached by the IMP Imap Client cache object.   
You should not be caching any FETCH details in activesync code.

michael

___________________________________
Michael Slusarz [slusarz at horde.org]



More information about the dev mailing list