Subject: Re: [lemonade] Another QRESYNC race condition

From: Timo Sirainen <[email-masked]>
Date: Wed, 11 Jun 2008 14:52:05 +0300

On Sat, 2008-05-03 at 03:17 +0300, Timo Sirainen wrote:
> > After completing a full synchronization, the client MUST also take
> >    note of any unsolicited MODSEQ FETCH data items received from the
> >    server.  Whenever the client receives a tagged response to a command,
> >    it calculates the highest value among all MODSEQ FETCH data items
> >    received since the last tagged response.  If this value is bigger
> >    than the client's copy of the HIGHESTMODSEQ value, then the client
> >    MUST use this value as its new HIGHESTMODSEQ value.
> 
> Problem:
> 
> C1: a store 1 +flags \seen
> S1: * 1 FETCH (FLAGS (\Seen) MODSEQ (1))
> S1: a OK
> 
> C2: b expunge
> S2: * VANISHED 1234
> S2: b OK [HIGHESTMODSEQ 2]
> 
> C1: c store 1 -flags \seen
> S1: * 1 FETCH (FLAGS () MODSEQ (3))
> S1: c OK
> 
> If C1 disconnects here, the next resync won't show that UID 1234 was
> expunged, because it uses 3 as the last seen HIGHESTMODSEQ.

What do you think about this solution:

If server sends untagged FETCH replies with MODSEQ fields but there are
pending EXPUNGE/VANISHED replies, the server sends HIGHESTMODSEQ which
is below the EXPUNGEs' modseq.

Example solving the above problem:

C1: a store 1 +flags \seen
S1: * 1 FETCH (FLAGS (\Seen) MODSEQ (1))
S1: a OK

C2: b expunge
S2: * VANISHED 1234
S2: b OK [HIGHESTMODSEQ 2]

C1: c store 1 -flags \seen
S1: * 1 FETCH (FLAGS () MODSEQ (3))
S1: * OK [HIGHESTMODSEQ 1]
S1: c OK

Or it could be in the tagged reply as well, doesn't really matter
(except it can't be used with STORE UNCHANGEDSINCE that fails with
[MODIFIED]).

(As an optimization the HIGHESTMODSEQ could also be sent after a
non-EXPUNGE/CLOSE command sends a VANISHED reply.)

Client logic would then be:

1. When receiving FETCH MODSEQs, keep track of the highest value but
don't update HIGHESTMODSEQ yet.

2. When untagged or tagged HIGHESTMODSEQ resp code is received, set
highest FETCH MODSEQ value to zero. Always update the current
HIGHESTMODSEQ value with the given value, even if it shrinks.

3. When receiving a tagged reply process its resp code first. After
that if highest FETCH MODSEQ value is larger than HIGHESTMODSEQ, update
it.

After this change and making the server always send UID in FETCH replies
my QRESYNC stress tester (http://imapwiki.org/ImapTest) doesn't lose
changes anymore. If you want to try yourself, this command works pretty
well:

./imaptest checkpoint=1 logout=10 clients=2 random qresync delay=1

_______________________________________________
lemonade mailing list
[email-masked]
https://www.ietf.org/mailman/listinfo/lemonade
Supplemental Web Site:
http://www.standardstrack.com/ietf/lemonade