Re: [IndexedDB] Client API state after calling deleteIndex and deleteObjectStore

On Fri, Jul 22, 2011 at 9:51 AM, Israel Hilerio <israelh@microsoft.com> wrote:
> On Thursday, July 14, 2011 5:27 PM, Israel Hilerio wrote:
>> On Thursday, July 14, 2011 1:57 PM, Jonas Sicking wrote:
>> > On Thu, Jul 14, 2011 at 1:20 PM, Israel Hilerio <israelh@microsoft.com>
>> wrote:
>> > > On Wednesday, July 13, 2011 2:02 PM, Jonas Sicking wrote:
>> > >> On Wed, Jul 13, 2011 at 11:39 AM, Israel Hilerio
>> > >> <israelh@microsoft.com>
>> > >> wrote:
>> > >> > What should be the client state after a deleteIndex is called?
>> > >> > For example looking at the code below:
>> > >> >
>> > >> > 1. var index = objStore.index(indexName); 2.
>> > >> > objStore.deleteIndex(indexName); 3. try { 4.
>> > >> > index.openCursor().onerror = function (e) { log("failed to open
>> > >> > cursor"); } 5. } catch (ex) { 6.      log ("failed to call
>> > >> > openCursor"); 7. }
>> > >> >
>> > >> > Similar to our previous conversation around transaction.abort, it
>> > >> > seems that
>> > >> we would want to keep some knowledge on the client that the index
>> > >> was deleted at line #2 and therefore, line #4 will throw an
>> > >> exception that will be handled by line #6.  In this case, the
>> > >> onerror handler at line #4 will never be executed.
>> > >> >
>> > >> > Do you agree?
>> > >>
>> > >> Yes! I do think we need to modify the spec to specify this.
>> > >>
>> > >> > Would it be good enough to just throw an UNKNOWN_ERR or we could
>> > >> create a new error code for this (e.g. CALLER_ERR or OBJECT_ERR).
>> > >>
>> > >> I would say NOT_ALLOWED_ERR or NOT_FOUND_ERR would be ok for
>> this
>> > >> case.
>> > >>
>> > >> > Also, what should happen to deleteObjectStore when it is called
>> > >> > in a similar
>> > >> situation:
>> > >> >
>> > >> > 1. var objStore = db.createObjectStore(osName, {keyPath: "name"}); 2.
>> > >> > db.deleteObjectStore(osName); 3. try { 4.
>> > >> > objStore.index(indexName); 5. } catch (ex) { 6.     Log ("failed
>> > >> > to call index"); 7. }
>> > >> >
>> > >> > I would also expect us to keep knowledge on the client that the
>> > >> > objStore
>> > >> was deleted at line #2 and therefore not allow line #4 from queuing
>> > >> up a request but fail fast with an exception.  We could throw the
>> > >> same exception as the example above.
>> > >> >
>> > >> > Do you agree?
>> > >>
>> > >> Yup. Seems identical to the situation you described above.
>> > >>
>> > >> By the way, I assume this is only relevant during VERSION_CHANGE
>> > >> transactions, right?
>> > >>
>> > >> Another tricky situation is what to do with code like
>> > >>
>> > >> 1. var index = objStore.index(indexName); 2. req = index.get(2); 3.
>> > >> req.onsuccess = function() { log("didn't fail, value is" + req.result) }; 4.
>> > >> req.onerror = function() { log("error was fired") }; 5.
>> > >> objStore.deleteIndex(indexName);
>> > >>
>> > >> I don't feel strongly what should happen. From an implementation
>> > >> point of view it might be easy either way. In fact I think in the
>> > >> Gecko implementation it might be easier to the request succeed and
>> > >> deliver the same data as if the index hadn't been deleted, than to
>> > >> let it fail. This is because all requests run on the same database
>> > >> thread (in order to ensure that they run in the proper order), and
>> > >> so by the time the index is deleted, we have already read data out from
>> it.
>> > >>
>> > >> From a user point of view it might be slightly more useful if the
>> > >> request succeeds, but it also seems quite ok to require that people
>> > >> don't delete an index or objectStore unless they don't expect to
>> > >> get more
>> > data from it.
>> > >>
>> > >> / Jonas
>> > >
>> > > We agree with you that we should let the previously queued up
>> > > operations
>> > finish before the deleteIndex or deleteObjectStore impacts them.
>> > However, after the deleteIndex or deleteObjectStore are executed in
>> > the client, we don't want to allow further calls to be invoked on
>> > these objects.  We want to immediately throw an exception
>> > (NOT_ALLOWED_ERR).  This implies that the client APIs don't have to
>> > wait for the deleteIndex and deleteObjecStore to be processed by the
>> > server and that the source objects will keep some type of information
>> > about their deleted state.  It seems a waist of cycles, to allow these
>> > operations to be queued on the server to find out that the source objects
>> don't exists any more.
>> > >
>> > > We believe this simplifies the programming model and makes it more
>> > deterministic.
>> > >
>> > > What do you think?
>> >
>> > It sounds like we agree!
>> >
>> > To make sure we're on the same page, here's pulling all the examples
>> > together.
>> >
>> >
>> > 1. var index = objStore.index(indexName); 2.
>> > objStore.deleteIndex(indexName); 3. try {
>> > 4.       index.openCursor().onerror = function (e) { log("failed to
>> > open cursor"); }
>> > 5. } catch (ex) {
>> > 6.      log ("failed to call openCursor");
>> > 7. }
>> >
>> > Here the openCursor call on line 4 should throw, causing the call on
>> > line 6 to execute next. The onerror assignment never happens as the
>> > exception is thrown before that, and thus the log call on line 4 is never
>> called.
>> >
>> >
>> > 1. var objStore = db.createObjectStore(osName, {keyPath: "name"}); 2.
>> > db.deleteObjectStore(osName); 3. try {
>> > 4.     objStore.index(indexName);
>> > 5. } catch (ex) {
>> > 6.     log("failed to call index");
>> > 7. }
>> >
>> > Here the index call on line 4 should throw, causing the call on line 6
>> > to execute next.
>> >
>> >
>> > 1. var index = objStore.index(indexName); 2. req = index.get(2); 3.
>> > req.onsuccess = function() { log("didn't fail, value is" + req.result) }; 4.
>> > req.onerror = function() { log("error was fired") }; 5.
>> > objStore.deleteIndex(indexName); 6.
>> > db.deleteObjectStore(objStore.name);
>> >
>> > Here the function assigned to the onsuccess property on line 3 will
>> > eventually be called and will log whatever value is stored for in the
>> > index at key 2 (or if no such value was stored, it'll log
>> > <undefiend>). The function assigned to the onerror handler on line 4 is
>> never called.
>> >
>> > The same thing would happen if line 5 was removed as removing an
>> > objectStore also removes all its indexes.
>> >
>> >
>> > Another even more complex scenario not brought up yet:
>> >
>> > 1. var index = objStore.index(indexName); 2. req = index.openCursor(); 3.
>> > req.onsuccess = function() { var curs = res.result; if (curs) {
>> > log("found value " + curs.value); curs.continue(); } }; 4. req.onerror
>> > = function() { log("error was
>> > fired") }; 5. objStore.deleteIndex(indexName);
>> >
>> > In this scenario the function assigned to the onsuccess property on
>> > line 3 is called once and will log the first value in the index.
>> > However when that function calls curs.continue, the call to continue
>> > will throw an exception as the index has been deleted.
>> >
>> > Hence the onsuccess function will only be called once, and the onerror
>> > function won't be called at all.
>> >
>> >
>> > Does this match your understanding?
>> >
>> > / Jonas
>>
>> Thanks for putting the last example together.
>> Yes, this matches our understanding.
>>
>> Israel
>>
>
> Jonas,
>
> Would it be good enough to document the above examples under the deleteIndex and deleteObjectStore APIs, respectively? Or do you believe we should add some text to the API descriptions to make this more clear?  In addition, I believe we should expand the explanation for when NOT_ALLOWED_ERR can be thrown to accommodate this case.
>
> Let me know what you prefer?

It would probably also be the most consistent to ensure that all
functions that create requests explicitly mention that a
NOT_ALLOWED_ERR is thrown if the source has been removed. So in the
cases where these functions already throw NOT_ALLOWED_ERR, adding this
additional condition to that description would be a good idea.

Does that answer the question?

Oh, and yes, expanding the explanation for NOT_ALLOWED_ERR seems like
a good idea.

/ Jonas

Received on Friday, 22 July 2011 20:47:05 UTC