On Fri, Jul 22, 2011 at 9:51 AM, Israel Hilerio <[email protected]> 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 <[email protected]> >> wrote: >> > > On Wednesday, July 13, 2011 2:02 PM, Jonas Sicking wrote: >> > >> On Wed, Jul 13, 2011 at 11:39 AM, Israel Hilerio >> > >> <[email protected]> >> > >> 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
