Re: [IndexedDB] Atomic schema changes
On Sat, Jun 26, 2010 at 11:44 AM, Jeremy Orlow jor...@chromium.org wrote: On Sat, Jun 26, 2010 at 10:09 AM, Jonas Sicking jo...@sicking.cc wrote: On Fri, Jun 25, 2010 at 2:43 AM, Jeremy Orlow jor...@chromium.org wrote: I'm OK with making createObjectStore/createIndex synchronous. It would definitely make such code cleaner and I don't see a major downside, but at the same time I feel like this API is starting to get kind of ad-hoc and unintuitive to a new user. Having the create and the remove functions completely different and in different places seems weird. So I agree with either A or leaving things as originally proposed by Jonas in [IndexDB] Proposal for async API changes. Well, there's no reason not to make the same changes to removeObjectStore/removeIndex. Though the more I think with this design createObjectStore and removeObjectStore can stay on IDBDatabase and simply throw if called outside the appropriate transaction callback. Here is the revised proposal: interface IDBDatabase { ... IDBObjectStore createObjectStore (in DOMString name, in optional DOMString keyPath, in optional boolean autoIncrement); void removeObjectStore (in DOMString storeName); ... }; interface IDBObjectStore { ... IDBIndex createIndex (in DOMString name, in DOMString keyPath, in optional boolean unique); IDBRequest removeIndex (in DOMString indexName); ... }; Where createObjecStore/createIndex throws if a objectStore or index of the given name already exists, if the keyPath has an invalid syntax, or if the function is called when not inside a version-change transaction callback. And removeObjectStore/removeIndex throws if the objectStore or index doesn't exist or if the function is called when not inside a version-change transaction callback. Throwing if not inside the right type of callback isn't a super clean solution, but is really not that different from how add/put throws if called when not inside a READ_WRITE transaction. Just to be clear, no async function (one that returns an IDBRequest) should _ever_ throw. (They should only call onerror.) I assume you didn't mean add/put throws literally? Well, there's no reason we couldn't make add/put throw if called from inside the wrong type of transaction. I guess I don't feel strongly about it, but it seems to me that calling put from inside a READ_ONLY transaction is a much bigger mistake than writing a duplicate key or running out of disc space. Additionally it's a situation where we synchronously know that there is a bug in the program. When this came up before, the thought was that it'd be confusing to web developers which errors would raise immediately and which would call the error callback. My feeling is that consistency is more useful than raising right away for errors like this. (Plus, if we find it hard to get web developers to do any error checking, it seems even harder to get them to do it in 2 ways. :-) Well, I wouldn't expect them to check for put-in-wrong transaction, and thus have that error bubble up and become a top level error, which is handled through the usual error reporting mechanisms which should alert the developer of a bug in their code. So it's actually intentional that this error is handled different from other errors. But if everyone else feels otherwise I'll shut up and accept that strategy. But, I feel pretty strongly that a setVersion/schema change transaction should not simply kill off anything else currently running. The reason is that it's not hard for apps to recover from a connection failing, but it is hard to handle a transaction failing in an unpredictable way. Especially static transactions (which should rarely fail committing since serialization can be guaranteed before the transaction starts). That might be a good idea for v1. I was planning on doing a separate thread for setVersion, but maybe it's tied enough to the topic of schema changes that it makes sense to bring up here. What I suggest is that when setVersion is called, we fire 'versionchange' event on all other open IDBDatabase objects. This event contains information of what the desired new version number is. If no other IDBDatabase objects are open for the specific database, no 'versionchange' events are fired. This allows pages using the old schema version to automatically save any pending data (for example any draft emails) and display UI to the user suggesting that the tab be closed. If possible without dataloss, the tab could even reload itself to automatically load an updated version of the page which uses the new schema version. The 'versionchange' event would use an interface like interface IDBVersionEvent : IDBEvent { readonly attribute string version; }; First of all, what I was originally advocating (sorry
Re: [IndexedDB] Atomic schema changes
On Sun, Jun 27, 2010 at 8:27 AM, Jonas Sicking jo...@sicking.cc wrote: On Sat, Jun 26, 2010 at 11:44 AM, Jeremy Orlow jor...@chromium.org wrote: On Sat, Jun 26, 2010 at 10:09 AM, Jonas Sicking jo...@sicking.cc wrote: On Fri, Jun 25, 2010 at 2:43 AM, Jeremy Orlow jor...@chromium.org wrote: I'm OK with making createObjectStore/createIndex synchronous. It would definitely make such code cleaner and I don't see a major downside, but at the same time I feel like this API is starting to get kind of ad-hoc and unintuitive to a new user. Having the create and the remove functions completely different and in different places seems weird. So I agree with either A or leaving things as originally proposed by Jonas in [IndexDB] Proposal for async API changes. Well, there's no reason not to make the same changes to removeObjectStore/removeIndex. Though the more I think with this design createObjectStore and removeObjectStore can stay on IDBDatabase and simply throw if called outside the appropriate transaction callback. Here is the revised proposal: interface IDBDatabase { ... IDBObjectStore createObjectStore (in DOMString name, in optional DOMString keyPath, in optional boolean autoIncrement); void removeObjectStore (in DOMString storeName); ... }; interface IDBObjectStore { ... IDBIndex createIndex (in DOMString name, in DOMString keyPath, in optional boolean unique); IDBRequest removeIndex (in DOMString indexName); ... }; Where createObjecStore/createIndex throws if a objectStore or index of the given name already exists, if the keyPath has an invalid syntax, or if the function is called when not inside a version-change transaction callback. And removeObjectStore/removeIndex throws if the objectStore or index doesn't exist or if the function is called when not inside a version-change transaction callback. Throwing if not inside the right type of callback isn't a super clean solution, but is really not that different from how add/put throws if called when not inside a READ_WRITE transaction. Just to be clear, no async function (one that returns an IDBRequest) should _ever_ throw. (They should only call onerror.) I assume you didn't mean add/put throws literally? Well, there's no reason we couldn't make add/put throw if called from inside the wrong type of transaction. I guess I don't feel strongly about it, but it seems to me that calling put from inside a READ_ONLY transaction is a much bigger mistake than writing a duplicate key or running out of disc space. Additionally it's a situation where we synchronously know that there is a bug in the program. When this came up before, the thought was that it'd be confusing to web developers which errors would raise immediately and which would call the error callback. My feeling is that consistency is more useful than raising right away for errors like this. (Plus, if we find it hard to get web developers to do any error checking, it seems even harder to get them to do it in 2 ways. :-) Well, I wouldn't expect them to check for put-in-wrong transaction, and thus have that error bubble up and become a top level error, which is handled through the usual error reporting mechanisms which should alert the developer of a bug in their code. So it's actually intentional that this error is handled different from other errors. But if everyone else feels otherwise I'll shut up and accept that strategy. Lets start another thread and examine this. If all the errors can pretty clearly/intuitively be broken into two groups, then maybe this does make sense. (I'll try to do it later today unless you beat me to it.) But, I feel pretty strongly that a setVersion/schema change transaction should not simply kill off anything else currently running. The reason is that it's not hard for apps to recover from a connection failing, but it is hard to handle a transaction failing in an unpredictable way. Especially static transactions (which should rarely fail committing since serialization can be guaranteed before the transaction starts). That might be a good idea for v1. I was planning on doing a separate thread for setVersion, but maybe it's tied enough to the topic of schema changes that it makes sense to bring up here. What I suggest is that when setVersion is called, we fire 'versionchange' event on all other open IDBDatabase objects. This event contains information of what the desired new version number is. If no other IDBDatabase objects are open for the specific database, no 'versionchange' events are fired. This allows pages using the old schema version to automatically save any pending data (for example any draft emails) and display UI to