Fixing pollForUpdate() (multiple tab problem)



I've spent some time researching the "doesn't work if you open two
tabs" problem. It turns out that this is a client-side limit
problem. Take the case of mozilla, it allows two concurrent requests
to the same server (defined as hostname + port pair) at the same time 
(or 8 if http keep_alive isn't used). In the case of yarrr with two
open tabs, we immediately reach this two request limit due to the
pollForChanges() call made by each tab. This means any other xmlrpc
call done after the two pollForChanges() calls will not be sent until
the polls return (never, or when you close one tab).

For mozilla, the "easy" fix for this problem is to add something like:
 user_pref("network.http.max-persistent-connections-per-server", 8);
 user_pref("network.http.max-connections-per-server", 16);
to your user.js preferences file. A similar preference may exist in IE.
However, I don't think this is an acceptable solution. Yarrr has to
work out of the box, without messing around with the webbrowser on at
least firefox and IE > 5.

The existance of pollForChanges() is extremely core for Yarrr. Without
it we just can't deliver a smooth experience with the chat and
collaborative editing parts. So, we need to look at ways to work
around this problem.

An obvious way is to connect to a different "server", by using the
fact that the port is part of what specifies a server. Say we use the
normal port (80 or 8080) for getting all the html, and for doing the
normal xmlrpc calls, but we also serve ports 2000-2100. We could then
tell the client what port to use for the pollForUpdate() call, such
that we never send a client on a specific ip to a port its already
using. This way clients will never "block" normal calls due to the
outstanding pollForUpdate call (there will always be one).

Additionally, by handling all the long running pollForUpdate() calls on
a separate port we can handle these in a different, more efficient
fashion. The way we do things now requires a thread in the server (out
of a limited pool) for each operation, which will be dedicated to the
request. For the case of pollForChanges() this means we'll always tie
up one thread per tab/window the user views. If we special cased the
poll there is no need for this, the http handler would just queue the
poll object and return.

The way I imagine this is that the client allocates a server side poll
object (actually, its likely auto-allocated using the clientid we send
in the webpage) that the client updates to what it currently is
interested in using normal xmlrpc calls. These xmlrpc calls then
return the url to use for the actual poll call. We call into that,
blocking for a change, and when the change happens we can use the
normal xmlrpc calls to figure out what changed (or it could be
returned by the call, but this might be complicated, see below). The
client reads all changed objects, and then updates the poll object and
loops. 

This all sounds nice, unfortunately there are more problems that arise
here. XMLHttpRequest, which is what the xmlrpc library uses to do the
http requests is normally limited in where it can do requests. By
default you can only connect to the host and port that the webpage was
downloaded from[1]. In IE you can change this by running IE with
reduced security settings, and in Mozilla you can change this by
signing all your javascript code and requesting elevated
permissions[2].

So, we can't do xmlrpc calls to the other port. What do we do then?
We do it like people did it in the old days, before XMLHttpRequest, we
use a hidden iframe[3]. Working with an iframe in this way is slightly
more limited than XMLHttpRequest. For instance, you can only GET, not
POST, meaning you can only send a limited amount of data to the
server. However, given that we use the normal xmlrpc protocol for all
complicated communication this should not be a problem. All we need is
the onload callback on the iframe to tell us that something did
change.

I've experimented a bit with the iframe approach, and it is able to
read data from a different port. So, I think this describes a possible
workaround to the pollForChanges() problems. It is somewhat ugly and
complicated, but I think it can result in a system that works in both
IE and FireFox without messing with any settings. I also think that
the messiness of the solution can be hidden pretty well, such that the
rest of the code is essentially unaffected. 

[1] http://www.mozilla.org/projects/security/components/jssec.html#sameorigin
[2] http://www.mozilla.org/projects/security/components/jssec.html#privs-list
[3] http://developer.apple.com/internet/webcontent/iframe.html

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 Alexander Larsson                                            Red Hat, Inc 
                   alexl redhat com    alla lysator liu se 
He's an uncontrollable shark-wrestling photographer for the 21st century. 
She's a sarcastic renegade museum curator with the soul of a mighty warrior. 
They fight crime! 




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]