Re: [IndexedDB] setVersion blocked on uncollected garbage IDBDatabases

On Wed, Feb 9, 2011 at 6:12 PM, Glenn Maynard <glenn@zewt.org> wrote:
> On Wed, Feb 9, 2011 at 8:39 PM, Jonas Sicking <jonas@sicking.cc> wrote:
>>
>> On Wed, Feb 9, 2011 at 5:26 PM, Glenn Maynard <glenn@zewt.org> wrote:
>> > Another related issue: what happens if a long-running number-cruncher
>> > worker
>> > keeps a database open while it works, to read data or output results?
>> > There's no API for sending versionchange events for IDBDatabaseSync, and
>> > it
>> > doesn't fit in any obvious way since it's inherently asynchronous.  I
>> > suppose the developer-side workaround would be to open the same database
>> > asynchronously in the UI thread just to listen for versionchange, and to
>> > terminate the thread when it's received.  Is that generally what's
>> > intended?
>>
>> This is a good point. We should add the ability to dispatch
>> versionchange events on IDBDatabaseSync. There is no reason we
>> couldn't just make it a event target and add a .onversionchange
>> property to it.
>>
>> Just because the object has some (or many, or only) synchronous
>> methods, doesn't mean it can't also dispatch events.
>
> That works provided your worker periocally returns to the caller, to allow
> events to be dispatched; otherwise the event will never be received.  That's
> usually the case--even for number-crunching workers, most use cases look
> like "receive a request, spend a few seconds doing calculations and I/O and
> return the result".
>
> Not all do--some number-crunching cases might take minutes to run.

That's true, but that's not really a problem with the IDBDatabaseSync
API, but rather with worker design. For example a worker could open
use the asynchronous IDBDatabase for a bit and then start doing a lot
of number crunching and synchronous FileReader/XMLHttpRequest
operations. We can asynchronously fire a event at the IDBDatabase
instance in the worker all we want, but as you point out, until the
worker returns to the event loop it won't be able to receive it.

We could add some sort of IDBDatabaseSync.versionChangePending
property which would allow a long-running script to check for pending
version changes and if so close the database. However it takes a fair
amount of work to use. With an event based interface all you need to
do is add a event handler once and then not worry any more about it.
With a .versionChangePending property, you have to add code to check
the property to every single inner loop where you can spend
significant amounts of time. This will quickly get out of hand as we
start adding more APIs like this which people will have to tend to in
their inner loops.

An alternative solution would be to add a
IDBDatabaseSync.onversionchange property along with an event. Then
asynchronously dispatch the event as with the asynchronous interface.
However if the event goes undispatched for X seconds, forcefully close
the IDBDatabaseSync instance. Note this means that as long as you
return to the event loop, even if you don't handle the event, the
IDBDatabaseSync won't be closed.

I'm not a huge fan of that solution though.

> The
> typical example is expensive renderers, such as a raytracer that may take a
> couple minutes to render a scene.  These sorts of tasks wouldn't want to
> return to the caller--being able to write these algorithms linearly rather
> than in an incremental, setTimeout-based fashion is a basic use case of
> workers.  That said, these are uncommon enough that it's the "asynchronous
> watcher in a separate thread" workaround seems acceptable.

Could be. And since we have worker.terminate() it is possible to
quickly terminate a worker which is using a database.

/ Jonas

Received on Thursday, 10 February 2011 02:51:37 UTC