.

Sunday, February 26, 2006

A simple, leak free, defensive XMLHttpRequest Wrapper #

As you may have known Internet Explorer is the king of the leakers.

And XMLHttpRequest (in other words "Microsoft.XMLHTTP" ActiveX component) is not an exception to this.

In this post, I will try to explain where the component may leak and how we can avoid those leaks.

Let us begin with a typical wrapper:

[LISTING 1]
var _this=XHRequest.prototype;
function XHRequest(){
this.init();
}

_this.init=function(){
var sourceElement=this;
this._xhr=this.getObject();
if(!this._xhr)return;
this._xhr.onreadystatechange=function(){
var obj=sourceElement.getObject();
if(obj.readyState==4){
/*
* 404: file not found.
* 200: OK.
* 304: reading from cache.
*/
if(obj.status==200 OR obj.status==304)
sourceElement.oncomplete(obj.responseText,obj.responseXML);
else
sourceElement.onerror(obj.status,obj.statusText);
}
};
};


where getObject may be defined as:

[LISTING 2]
_this.getObject=function(){
if(this._xhr)return this._xhr;
else if(window.XMLHttpRequest)return new XMLHttpRequest();
else if(window.ActiveXObject)
return new ActiveXObject("Microsoft.XMLHTTP");
else return null;
};


The problem is that, we have created a closure in Listing 1:



and closures between DOM world and JS world will cause a memory leak in IE.

To sort out this we will need to implement a few helpers:

First let us alter the onreadystatechange handler a bit:
... code snippped ...
/*
* 404: file not found.
* 200: OK
* 304: reading from cache.
*/
if(obj.status==200obj.status==304)
sourceElement.oncomplete(obj.responseText,obj.responseXML);
else sourceElement.onerror(obj.status,obj.statusText);
/*to prevent IE memory leak due to circular COM referencing.*/
sourceElement._cleanup();


And the _cleanup method as:

_this._cleanup=function(){
if(!this._xhr)return;

/*
* this._xhr.onreadystatechange = null generates
* a "type mismatch" error in IE.
* So, to release circular reference
* we delete this._xhr.onreadystatechange;
*
* Actually, either setting this._xhr=null
* or "delete"ing this._xhr.onreadystatechange
* is enough to prevent memory leak.
*
* That is, the first line of the code below
* is just added to be on the safe side.
*/
delete this._xhr.onreadystatechange;
this._xhr=null;
};


And, for the interested, here follows the entire lightweight
XMLHttp wrapper (which I am currently enhancing a lot and will fully integrate to the next version of sardalya. )

Sorry for the indentation and typos in the code. It is blogger's WYSIWYG mode's fault not mine :)

_this=XHRequest.prototype;
function XHRequest()
{
this.init();
}

_this.init=function()
{
var sourceElement=null;

this._xhr=this.getObject();
if(!this._xhr)return;

sourceElement=this;

this._xhr.onreadystatechange=function()
{
var obj=sourceElement.getObject();
if(obj.readyState==4)
{
if(obj.status==200 OR
obj.status==304)sourceElement.oncomplete(
obj.responseText,obj.responseXML);
else sourceElement.onerror(obj.status,obj.statusText);
sourceElement._cleanup();
}
};
};


_this.getObject=function()
{
if(this._xhr)return this._xhr;
else if(window.XMLHttpRequest)return new XMLHttpRequest();
else if(window.ActiveXObject)return new ActiveXObject("Microsoft.XMLHTTP");
else return null;
};

_this.finalize=function()
{
if(!this._xhr)return;
this._cleanup();
};

_this.get=function(strURL,_blnSync)
{
if(!this._xhr)return null;
if(!_blnSync)_blnSync=false;

this._xhr.open("GET",strURL,!_blnSync);
this._xhr.send(null);
};

_this.getSynchronized=function(strURL)
{
this.get(strURL,true);
};

_this.abort=function()
{
if(this._xhr)this._xhr.abort();
this._cleanup();
};

_this._cleanup=function()
{
if(!this._xhr)return;
delete this._xhr.onreadystatechange;
this._xhr=null;
};

_this.oncomplete=function(strResponseText,objResponseXML)
{
alert("Completed everything.");
};

_this.onerror=function(intStatus,strStatusText)
{
alert("An error occured but my owner is too lazy to handle it.");
};

 bu yaziyi sevdin mi?  hemen una ekle!
 

Tuesday, February 14, 2006

To InnoDB or to MyIsam, that's the problem. #

I am currently designing the database schema for a high-load web application and I had some time to think on the famous MySQL optimization dilemma:
"Shall I use InnoDB, shall I user MyIsam, or shall I stay somewhere in between?".

[introduction]
As you may know MyIsam uses table-level locking and it performs best when there is a high number of selects but the data is not altered that much. On the other hand, InnoDB uses row-level locking; which allows selects and updates occur concurrently on a table.

Thus InnoDB may be faster, and is definitely more reliable, in a transactional enviroment where a lot of inserts /updates/deletes take place. InnoDB supports advanced features such as transactions, relational integrity and is fully ACID-compliant.
[/introduction]

First of all thanks God that it is most of the time possible to switch between the two table versions easily.

Here is a slow and dirty way:
  1. dump your database (you backup before doing something risky, don't you?)
  2. create a series of insert statements for your table data.
  3. drop your table and relations on it.
  4. recraete your table.
  5. insert the data back.
  6. create indexes and relations as necessary.
These steps work best when you cannot use

ALTER TABLE tblName CHANGE TYPE=
[MyIsam|InnoDB]

command for one reason or another.

Otherwise you can re-create your table simply with the above single-line SQL.

...

So here is the heuristic I apply to choose between the two table types:

Q: Does your web application have a high load?
Does it have a high number
of concurrent users at peak times?

If your answer is NO --> use MyIsam for all your tables.

Otherwise answer the following question:

Q: Is your application mission critical and you have
to preserve data integrity and sacrifice some speed
in order to keep the data in a consistent state?

If YES --> don't think for a second and go for InnoDB.

If NO it's better to use a hybrid setup of MyIsam and InnoDB tables:

So analyze your database structure for each table and ask the following questions for every single one of tables you have:

Q: Are there likely to be more selects on the table than
(insert/update/delete) operations?
[for instance a lookup table which is not changed
very often]

If YES --> use MyIsam.

Else answer the following question:

Q: Are there likely to be more inserts and fewer updates or deletes? (for instance if the users are building some sort of a category tree it is more probably that they will add new nodes than they will delete existing ones)

If YES-> use MyIsam.

If NO -> (updates and deletes will be relatively higher) use InnoDB.

...

Q: Are you still unsure?
Use MyIsam.

...

That's how I decide for the contents of my current db schema.

Hope that helps to someone out there as well.

 bu yaziyi sevdin mi?  hemen una ekle!
 



Recent Posts

RSS

RSS register icon

Other Blogs

Archive

Various

Sponsor

Profile Information

Browser I Suggest

Sponsor

Dikkatimi Çekenler