New version with slightly more correct cached edit handling. And I've added
a third client that is being a spam bot.
The state trace now looks like this:
Three clients, sync'd
server editHistory[0]:
Client 'Client1' at server revision 1 with document
Client 'Client2' at server revision 1 with document
Client 'Client3' at server revision 1 with document
Client3 is generating noise
server editHistory[0]:
server editHistory[1]: ++" Chatter";
Client 'Client1' at server revision 1 with document
Client 'Client2' at server revision 1 with document
Client 'Client3' at server revision 2 with document ++" Chatter";
Client2 has generated an edit, and it's in flight
server editHistory[0]:
server editHistory[1]: ++" Chatter";
Client 'Client1' at server revision 1 with document ++"Hello"; with edit in
flight ++"Hello";
Client 'Client2' at server revision 1 with document
Client 'Client3' at server revision 2 with document ++" Chatter";
Client2 has generated matching edit, also in flight
server editHistory[0]:
server editHistory[1]: ++" Chatter";
Client 'Client1' at server revision 1 with document ++"Hello"; with edit in
flight ++"Hello";
Client 'Client2' at server revision 1 with document ++"Hello"; with edit in
flight ++"Hello";
Client 'Client3' at server revision 2 with document ++" Chatter";
Client1 has handbasket edit cached
server editHistory[0]:
server editHistory[1]: ++" Chatter";
Client 'Client1' at server revision 1 with document ++"Hello"; with edit in
flight ++"Hello"; with cached edit __5; ++" Going to hell";
Client 'Client2' at server revision 1 with document ++"Hello"; with edit in
flight ++"Hello";
Client 'Client3' at server revision 2 with document ++" Chatter";
Server has client2's edit in, and clients synced there
server editHistory[0]:
server editHistory[1]: ++" Chatter";
server editHistory[2]: ++"Hello"; __8;
Client 'Client1' at server revision 3 with document ++"Hello Chatter"; with
cached edit __5; ++" Going to hell"; __8;
Client 'Client2' at server revision 3 with document ++"Hello Chatter";
Client 'Client3' at server revision 3 with document ++"Hello Chatter";
Client3 is generating noise
server editHistory[0]:
server editHistory[1]: ++" Chatter";
server editHistory[2]: ++"Hello"; __8;
server editHistory[3]: __13; ++" Chatter";
Client 'Client1' at server revision 3 with document ++"Hello Chatter"; with
cached edit __5; ++" Going to hell"; __8;
Client 'Client2' at server revision 3 with document ++"Hello Chatter";
Client 'Client3' at server revision 4 with document ++"Hello Chatter
Chatter";
Server accepts client1's edit
server editHistory[0]:
server editHistory[1]: ++" Chatter";
server editHistory[2]: ++"Hello"; __8;
server editHistory[3]: __13; ++" Chatter";
server editHistory[4]: ++"Hello"; __21;
Client 'Client1' at server revision 3 with document ++"Hello Chatter"; with
cached edit __5; ++" Going to hell"; __8;
Client 'Client2' at server revision 3 with document ++"Hello Chatter";
Client 'Client3' at server revision 4 with document ++"Hello Chatter
Chatter";
Client3 is generating noise
server editHistory[0]:
server editHistory[1]: ++" Chatter";
server editHistory[2]: ++"Hello"; __8;
server editHistory[3]: __13; ++" Chatter";
server editHistory[4]: ++"Hello"; __21;
server editHistory[5]: __26; ++" Chatter";
Client 'Client1' at server revision 3 with document ++"Hello Chatter"; with
cached edit __5; ++" Going to hell"; __8;
Client 'Client2' at server revision 3 with document ++"Hello Chatter";
Client 'Client3' at server revision 6 with document ++"HelloHello Chatter
Chatter Chatter";
Client1's cached edit posted to server, and accepted
server editHistory[0]:
server editHistory[1]: ++" Chatter";
server editHistory[2]: ++"Hello"; __8;
server editHistory[3]: __13; ++" Chatter";
server editHistory[4]: ++"Hello"; __21;
server editHistory[5]: __26; ++" Chatter";
server editHistory[6]: __10; ++" Going to hell"; __24;
Client 'Client1' at server revision 7 with document ++"HelloHello Going to
hell Chatter Chatter Chatter";
Client 'Client2' at server revision 7 with document ++"HelloHello Going to
hell Chatter Chatter Chatter";
Client 'Client3' at server revision 7 with document ++"HelloHello Going to
hell Chatter Chatter Chatter";
From my perspective, the above shows that this simple c/s protocol based on
pushing edits to the server, and pulling a queue of edits back in separate
c->s calls, works. I'm not happy with how i'm modeling cached edits in the
client at this point, which means I need to re-do Client#acceptUpdates(),
probably using a strategy pattern...
brett
Ugh.
Reading back through my code after breakfast, and I realise that i'm
handling the cached edit while an edit is in flight incorrectly. And my
initial stabs at fixing it up are breaking. I think i need a bigger piece of
paper to figure this out...
brett
Heya Torben,
Post by Brett MorganI have attached a java class that I believe implements Daniel's scenario.
First off, note that I'm not implementing the wave federation algorithm, as
federation isn't my goal. My goal is to build web apps that use wave's OT.
That said, here is the output of the aforementioned java class showing that
the server and the two clients converge.
State of system after step 1
Client 'Client1' at server revision 1 with document
Client 'Client2' at server revision 1 with document
State of system after step 2
Client 'Client1' at server revision 1 with document ++"Hello"; with edit
in flight ++"Hello";
Client 'Client2' at server revision 1 with document
State of system after step 3
Client 'Client1' at server revision 1 with document ++"Hello"; with edit
in flight ++"Hello";
Client 'Client2' at server revision 1 with document ++"Hello"; with edit
in flight ++"Hello";
State of system after step 4
Client 'Client1' at server revision 1 with document ++"Hello"; with edit
in flight ++"Hello"; with cached edit __5; ++"Going to hell";
Client 'Client2' at server revision 1 with document ++"Hello"; with edit
in flight ++"Hello";
State of system after step 5
server editHistory[1]: ++"Hello";
server editHistory[2]: ++"Hello"; __5;
Client 'Client1' at server revision 2 with document ++"Hello"; with
cached edit __5; ++"Going to hell";
Client 'Client2' at server revision 2 with document ++"Hello";
State of system after step 7
server editHistory[1]: ++"Hello";
server editHistory[2]: ++"Hello"; __5;
server editHistory[3]: __10; ++"Going to hell";
Client 'Client1' at server revision 4 with document ++"HelloHelloGoing to
hell";
Client 'Client2' at server revision 4 with document ++"HelloHelloGoing to
hell";
Post by Torben WeisHi Brett,
thanks for the hint to your project. I did not know it before.
It had it's coming out party at LCA. And I think I'm going to rip it down
and start again, this time using long poll based notification. I couldn't do
long polls while I was targeting AppEngine as my deployment environment.
Post by Torben WeisHowever, I would like to see a proof (i.e. a short explanation is
sufficient) how you intend to solve the problem I have mentioned.
Running code is no proof :-)
If running code doesn't merit existence proof status, then i'm fucked. =)
Post by Torben WeisFor some reasons I strongly doubt that your code (or any possible code)
can handle this without changes to the C/S protocol.
The client/server protocol in the FedOne code base, unless i miss my
guess, isn't doing OT.
Post by Torben WeisYour application seems to be different anyway. If I am not mistaken (I
just read the wave you mentioned) you are running
a web client which connects to your web server which connects to FedOne.
Right?
Heh, no. I'm not using FedOne, just the OT component of FedOne. I'm
building out the capacity to be able to have gwt web clients running OT sync
with a webserver. It works, but I lack the theoretical grounding to prove
it.
Post by Torben WeisThe problem I mentioned is between your web server and FedOne. In my case
it is between QWaveClient and FedOne.
Your web app can of course recover as long as FedOne and your web server
are stable. But what happens if your
WebServer crashes in an unfortunate moment? Your code will suffer from
the very problem I described.
If the web server goes down with unsync'd state, everything goes shiny. At
this point I force the clients to drop all state and reload.
Post by Torben WeisHowever, would like to be proven wrong here since this would give me a
solution to my initial problem :-)
Sorta, kinda, maybe.
Post by Torben WeisGreetings
Torben
Post by Brett MorganActually, no, OT deals with this case. My almost working code that I
presented at LCA2010 deals with this edge case. Unfortunately it has bugs,
and dies in the arse randomly. Sigh.
https://wave.google.com/wave/#restored:wave:googlewave.com!w%252BTBvx4ehoA<https://wave.google.com/wave/#restored:wave:googlewave.com%21w%252BTBvx4ehoA>
http://code.google.com/p/wave-ot-editor/source/browse/#svn/wave-ot-editor
I can put together a JUnit test case showing that this case actually
stabilises using the Wave OT code, if that would help...
Post by Torben WeisHi Brett,
thanks for the suggestion.
However, it seems to me that this approach is not completely correct.
Imagine two clients which are sending a delta against the same server
version.
The delta says to insert "Hello" at some position in a blip.
The correct outcome is "HelloHello" being inserted.
Now one client fails to submit its delta, the other one succeeds.
The client that failed cannot detect that it failed, because the other
delta looks exactly the same. Thus, in the end "Hello" will be inserted
only once.
I agree that this is an academic corner case, but I see no solution for this
when relying on delta comparisons.
Greetings
Torben
Post by Brett MorganIf you are transforming your docops, you can compare the docops coming
back down for equality. You are doing client side transformations, right?
org.waveprotocol.wave.model.operation.OpComparators is the FedOne code
for comparing equality of ops. Which, after a whole bunch of edge case
DocOpUtil.toConciseString(a).equals(DocOpUtil.toConciseString(b))
In short, comparing docops for equality is easy, as long as you keep
transforming your docops...
Post by Torben WeisHi James,
How about when the client connects to the server again it does a
Post by James Purserhistory
check against the known good deltas it has sent out. If the last delta
it sent out isn't in the history, then it hasn't been received.
The problem is that this is impossible. How should QWaveClient
recognize a delta as
being its own? The server has perhaps transformed the delta, i.e.
simple delta comparison
is not possible and looking at version numbers does not help either.
Greetings
Torben
Post by James Purser--
James Purser
http://wavingtheshiny.collaborynth.com.au
Skype: purserj1977
--
You received this message because you are subscribed to the Google
Groups "Wave Protocol" group.
.
To unsubscribe from this group, send email to
.
For more options, visit this group at
http://groups.google.com/group/wave-protocol?hl=en.
--
---------------------------
Prof. Torben Weis
Universitaet Duisburg-Essen
--
You received this message because you are subscribed to the Google
Groups "Wave Protocol" group.
To unsubscribe from this group, send email to
.
For more options, visit this group at
http://groups.google.com/group/wave-protocol?hl=en.
--
Brett Morgan http://domesticmouse.livejournal.com/
--
You received this message because you are subscribed to the Google
Groups "Wave Protocol" group.
To unsubscribe from this group, send email to
.
For more options, visit this group at
http://groups.google.com/group/wave-protocol?hl=en.
--
---------------------------
Prof. Torben Weis
Universitaet Duisburg-Essen
--
You received this message because you are subscribed to the Google
Groups "Wave Protocol" group.
To unsubscribe from this group, send email to
.
For more options, visit this group at
http://groups.google.com/group/wave-protocol?hl=en.
--
Brett Morgan http://domesticmouse.livejournal.com/
--
You received this message because you are subscribed to the Google
Groups "Wave Protocol" group.
To unsubscribe from this group, send email to
.
For more options, visit this group at
http://groups.google.com/group/wave-protocol?hl=en.
--
---------------------------
Prof. Torben Weis
Universitaet Duisburg-Essen
--
You received this message because you are subscribed to the Google Groups
"Wave Protocol" group.
To unsubscribe from this group, send email to
.
For more options, visit this group at
http://groups.google.com/group/wave-protocol?hl=en.
--
Brett Morgan http://domesticmouse.livejournal.com/
--
Brett Morgan http://domesticmouse.livejournal.com/
--
Brett Morgan http://domesticmouse.livejournal.com/