One of the complaints I received early on about the asynchronous storage API was that it wasn’t faster to call
executeAsync compared to
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
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.