Sunday, June 20, 2010

As3 ArrayCollection Sort "Feature"

Consider my confusion when I setup the debugger:

this._listData.owner.dataProvider.getItemIndex(this._data) = -1 [0xffffffff]
this._listData.owner.dataProvider.getItemAt(11)===this._data = true

As a background you should know that this._listData.owner.dataProvider is an ArrayCollection. Based on what I know about "equality" in as3 the above is an impossible situation.

this._listData.owner.dataProvider.getItemAt(11)===this._data

That means that the 2 reference points to the same object. So if the 11th element is same that this.data why is it not found in the collection?????

Well the explanation is filed as a bug @Adobe. The problem is that the bug is more like an undocumented feature:
If you set a sort on the collection and the sort's comparator has a bug or simply does not pass the equality check for the same object(sounds like a bug) than you get to see the above.

In my case the trials are not over. The comparator's equality does work...

After hours of testing and heated debates..I spare you details... here is the explanation:

Our sort comparator used a mutable variable that described sort order ASC or DESC. Because the variable was mutable, it was changed by other things in the application. Leading to a an unpleasant and hard to debug problem:
  1. We create a sort function and assign it to an ArrayCollection.
  2. We add records to the ArrayCollection and call sort.
  3. Change the sort order variable.
  4. Call getItemIndex(this._data) and get -1
The problem is that the internals of the Collection assume that collection is sorted(it is not sorted by the sort as of #3). It tries to walk a tree(I assume after debug) using the comparator, but because the tree was created with a different sort function the tree walking (search) will fail.

Lesson #1: It is very important that any data that is in the sort function that is not passed as itemA/itemB can not change. If it needs to change recreate the sort/comparator. 

Lesson #2: Use a sort/comparator if you want to modify the default behavior of getItemIndex(). If you want to allow for customizing equality, use a Sort object on an ArrayCollection.  

Sunday, February 21, 2010

No RPC for Async IO. A case for Flash As3 Thrift Server over HTTP Full Duplex.

Recently I was playing with Thrift in the hope of replacing BlazeDS. Using an existing patch I was able to make a Thrift client in AS3 and send messages to Java, even get return values. However I faced a few strange things:


  1. Flash unlike Java does not support blocking IO for network operations( Java in the other hand has no async IO like Flash, not until 1.7 nio2). At the same time Flash also have no concept of threads.
  2. Any RPC call I made from flash to java, needed callback handlers in Flash, to handle the return values.
In traditional Java remote calls, even most HTTP based remote call we seem to make a fundamental assumption that the client is blocked waiting for response until the server processing is complete. That assumption falls apart in Flash.

The basic As3 Thrift Http client creates a new http call for each method invocation. The flash clients send the request, and moves on. To illustrate the problem:

In Java:
  1. call service A, wait until returns Foo.
  2. call service B and send Foo.
In Flash:
  1. call Service A, add method gotResponse as subscriber for the return value, move on and do other things.
  2. gotResponse called with Foo, call serviceB with Foo. 
Be Java or Flash if your application has many small messages this is somewhat wasteful. The HTTP headers often times are bigger that thrift payload. Opening and closing all these connections have a fixed cost overhead.

In my previous post I talked about using Http Chunk encoding, to reuse the open socket, HTTP request.

The problem is however that Thrift messaging API, is built with the assumptions of blocking io. The clients assume exclusive use of the transport, multiple clients using the same transport is kinda tricky to implement, since the transport does not know when one message starts or ends.

The simple way to solve the problem is to serialize access to the RPC client. The problem with serialized access is that it takes a long time.

Than I noticed oneway message and I think my problems are solved:


See instead of having callback methods for each RPC invocation, in an environment with Async IO we should just use one way messages.

In my case Flash as client sends one way messages to Java server. Once a message is processed on the Java Server side, Java will send one way messages to the Flash server.

Having mutexes on the oneway messaging clients only serializes message sending, which is an improvement over having to wait for a response before sending the next messages.

In addition this method easily supports sending events from a Java server to a flash client, without the client having to poll for it.

I hope this explanation was somewhat tought provoking and my patch for Full duplex Java and As3 clients will get accepted.