One of the complaints I received early on about the asynchronous storage API was that it wasn’t faster to call executeAsync
compared to execute
or executeStep
on the calling thread. This was largely the case because people were testing the function call without any other IO going on, which isn’t going to always be the case for our users. People tend to have more than one application running on their computer doing something, and that something can often hit the disk. The culprit of the slowdown was recreating the sqlite3_stmt object for each call to executeAsync
.
With my work on the asynchronous location bar, I wanted to speed up the call to executeAsync
to make it as fast as possible so autocomplete look ups would be quick. To accomplish this, we now cache the asynchronous sqlite3_stmt
object so we don’t recreate it on every call to executeAsync
. This amortizes the cost that was causing the asynchronous API to be slower than the synchronous one.
This solution is not sufficient, however, if you bind parameters to the statement before calling executeAsync
. This is because binding parameters stores state on the underlying sqlite3_stmt
object, and we can’t store that information on it because it could be in use on the background thread. To get around this issue, I reuse a code from the recent asynchronous storage API addition to store the bound values in memory and then bind them at the time of execution on the background thread. Andrew Sutherland and I were both very happy at how small this patched ended up being as a result of good API design in the past.
The bonus with this two step solution is that we’ve also completely removed the possibility of lock contention inside of the SQLite library on the calling thread of executeAsync
. If you have a long running sqlite3_step
command on the background thread, this could block your call to one of the binding calls or executeAsync
, which is undesirable.
This code is checked in on mozilla-central, and will be a part of Gecko 1.9.2.