WebKit Bugzilla
New
Browse
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
RESOLVED FIXED
Bug 91123
IndexedDB: inject index keys on cursor/objectstore/index get success handlers
https://bugs.webkit.org/show_bug.cgi?id=91123
Summary
IndexedDB: inject index keys on cursor/objectstore/index get success handlers
Alec Flett
Reported
2012-07-12 11:22:11 PDT
Once
bug 90923
lands, we'll be able to full implement this. Note that this doesn't cover the createIndex() case
Attachments
Patch
(37.48 KB, patch)
2012-07-25 11:01 PDT
,
Alec Flett
no flags
Details
Formatted Diff
Diff
Patch
(48.95 KB, patch)
2012-07-25 15:58 PDT
,
Alec Flett
no flags
Details
Formatted Diff
Diff
Patch
(49.03 KB, patch)
2012-07-25 16:49 PDT
,
Alec Flett
no flags
Details
Formatted Diff
Diff
Patch
(55.85 KB, patch)
2012-07-26 14:17 PDT
,
Alec Flett
no flags
Details
Formatted Diff
Diff
Patch
(55.92 KB, patch)
2012-07-26 15:37 PDT
,
Alec Flett
no flags
Details
Formatted Diff
Diff
Patch
(56.34 KB, patch)
2012-07-26 16:01 PDT
,
Alec Flett
no flags
Details
Formatted Diff
Diff
Patch
(56.31 KB, patch)
2012-07-26 16:10 PDT
,
Alec Flett
no flags
Details
Formatted Diff
Diff
Show Obsolete
(6)
View All
Add attachment
proposed patch, testcase, etc.
Alec Flett
Comment 1
2012-07-25 11:01:02 PDT
Created
attachment 154394
[details]
Patch
Alec Flett
Comment 2
2012-07-25 11:03:48 PDT
finally finally the tree is almost ready for me to land this. This is the final patch to allow get/put/update to deal with renderer-side key injection. This leaves around a lot of cruft because the the patch for createIndex is still coming. This particular patch includes that #include-reduction that I did, so you can ignore that stuff, it will be gone from the final patch and I'll update the patch here when webkit rolls next. jsbell/dgrogan: mind taking a look.
Joshua Bell
Comment 3
2012-07-25 12:23:16 PDT
Comment on
attachment 154394
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=154394&action=review
> Source/WebCore/ChangeLog:3 > + IndexedDB: inject index keys on cursor/objectstore/index get succes handlers
Typo "succes" -> "success"; I updated the bug itself.
> Source/WebCore/ChangeLog:19 > + assertion was removed from IDBBindingUtilities.
Haven't gotten to that point in the patch, but it seems like we could either: * Do an extract and only inject if they differ (so keep the assert) * Modify the assert so that it's okay if the value being injected is the same as the current value ... But now that I've gotten to that point, I agree that the binding utilities should stay "pure" and not be enforcing this logic. So I'd be tempted to add in an debug-only logic at the inject...() call site that either the value is not there or the value is there and matches what we'd inject.
> Source/WebCore/ChangeLog:26 > + No new tests because this is a performance refactoring, and actual
Do we have any actual perf data on this? (I'm guessing "not yet", so might be worth being more conservative in the comments.)
> Source/WebCore/ChangeLog:27 > + behavior hasn't changed.
Do we have any existing tests where the index key path is the same as the store's key path and autoincrement is used?
> Source/WebCore/Modules/indexeddb/IDBCursor.cpp:161 > + } else {
The "if (usesInLineKeys) ..." code is really a runtime validation that the new value doesn't change the key. It seems like the "else" case here should run in any case so that nothing downstream needs to compute a key.
> Source/WebCore/Modules/indexeddb/IDBCursor.cpp:165 > + return objectStore->put(IDBObjectStoreBackendInterface::CursorUpdate, IDBAny::create(this), context, value, key, ec);
i.e. just pass m-currentPrimaryKey in here instead of key.
> Source/WebCore/Modules/indexeddb/IDBCursorBackendImpl.cpp:88 > + ASSERT_NOT_REACHED();
I believe this method can be removed as well as any dependents on it (IDBCursorBackendInterface.h, IDBCursorBackendProxy.cpp, WebIDBCursorImpl.cpp) - the WEBKIT_ASSERT_NOT_REACHED in WebIDBCursor::update() is all that's necessary to keep Chromium building if nothing is calling it.
> Source/WebCore/Modules/indexeddb/IDBObjectStore.cpp:105 > +static bool generateIndexKeysForValue(const IDBIndexMetadata& indexMetadata,
This never appears to return false?
> Source/WebCore/Modules/indexeddb/IDBObjectStore.cpp:109 > + RefPtr<IDBKey> indexKey = createIDBKeyFromSerializedValueAndKeyPath(objectValue, indexMetadata.keyPath);
Add ASSERT(indexKeys.get()); (or pass as reference)
> Source/WebCore/Modules/indexeddb/IDBObjectStore.cpp:142 > +PassRefPtr<IDBRequest> IDBObjectStore::put(IDBObjectStoreBackendInterface::PutMode putMode, PassRefPtr<IDBAny> source, ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, ExceptionCode& ec)
Nice simplification. :)
> Source/WebCore/Modules/indexeddb/IDBObjectStore.cpp:198 > if (key && !key->isValid()) {
By this point, the only case where key is NULL is if it's going to be autogenerated, correct?
> Source/WebCore/Modules/indexeddb/IDBObjectStoreBackendImpl.cpp:127 > + ASSERT_NOT_REACHED();
Same as above on removing this - only the WebIDBObjectStore::put() stub needs to remain, the ...BackendImpl, ...BackendInterface, ...BackendProxy and Web...Impl versions can go.
> Source/WebCore/Modules/indexeddb/IDBRequest.cpp:343 > void IDBRequest::onSuccess(PassRefPtr<SerializedScriptValue> prpSerializedScriptValue, PassRefPtr<IDBKey> prpPrimaryKey, const IDBKeyPath& keyPath)
This should only be used in response to an IDBObjectStore.get() or IDBIndex.get(), correct? In that case, the keyPath should match the keyPath of the request's source's "effectiveObjectStore" (not a real concept, but borrowing from IDBCursor), right? In that case... can we either drop the keyPath parameter or at least ASSERT that they match?
> Source/WebCore/Modules/indexeddb/IDBRequest.cpp:351 > + injectIDBKeyIntoSerializedValue(primaryKey, value, keyPath);
Don't need to wrap this line. Ideally this code would match the IDBCursor::setValueReady code. They seem to handle injection failures differently. (Thinking towards further refactors, it would be nice if the updated cursor key/primarykey/value were passed back in onSuccessWithContinuation, stashed in the IDBRequest itself (not the cursor) and then the key injection for cursors could be done in IDBRequest.)
> Source/WebCore/bindings/v8/IDBBindingUtilities.cpp:-104 > - ASSERT(!object->Has(indexOrName));
Agreed, let's keep this pure.
Alec Flett
Comment 4
2012-07-25 15:56:34 PDT
Comment on
attachment 154394
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=154394&action=review
Ok, nits addressed, new patch coming.
>> Source/WebCore/ChangeLog:19 >> + assertion was removed from IDBBindingUtilities. > > Haven't gotten to that point in the patch, but it seems like we could either: > * Do an extract and only inject if they differ (so keep the assert) > * Modify the assert so that it's okay if the value being injected is the same as the current value > ... > But now that I've gotten to that point, I agree that the binding utilities should stay "pure" and not be enforcing this logic. So I'd be tempted to add in an debug-only logic at the inject...() call site that either the value is not there or the value is there and matches what we'd inject.
I added (back) the assertions - they seem like reasonable checks
>> Source/WebCore/Modules/indexeddb/IDBCursor.cpp:161 >> + } else { > > The "if (usesInLineKeys) ..." code is really a runtime validation that the new value doesn't change the key. It seems like the "else" case here should run in any case so that nothing downstream needs to compute a key.
Well as they say, "it's complicated" :) it has to be set to null here mostly to get by other checks. But actually fix on the other end (In IDBObjectStore::put) is less complicated than simply passing m_currentPrimaryKey, so I did that.
>> Source/WebCore/Modules/indexeddb/IDBObjectStore.cpp:105 >> +static bool generateIndexKeysForValue(const IDBIndexMetadata& indexMetadata, > > This never appears to return false?
oh wow. Didn't even notice that I had removed all failure cases :) Fixed this and the other one in IDBObjectStoreImpl.cpp
> Source/WebCore/Modules/indexeddb/IDBObjectStore.cpp:198 > if (key && !key->isValid()) {
this is one of those subtle cases of if (key && !key->isValid()) rather than if (!key || !key->isValid()) - i.e. the extracted key value is present, but invalid.
> Source/WebCore/Modules/indexeddb/IDBRequest.cpp:343 > void IDBRequest::onSuccess(PassRefPtr<SerializedScriptValue> prpSerializedScriptValue, PassRefPtr<IDBKey> prpPrimaryKey, const IDBKeyPath& keyPath)
That's why this is like this - there isn't really enough in the way of breadcrumbs to track our way back to the equivalent of the effectiveObjectStore. I added some debug code, which also required implementing operator== on IDBKeyPath
>> Source/WebCore/Modules/indexeddb/IDBRequest.cpp:351 >> + injectIDBKeyIntoSerializedValue(primaryKey, value, keyPath); > > Don't need to wrap this line. > > Ideally this code would match the IDBCursor::setValueReady code. They seem to handle injection failures differently. > > (Thinking towards further refactors, it would be nice if the updated cursor key/primarykey/value were passed back in onSuccessWithContinuation, stashed in the IDBRequest itself (not the cursor) and then the key injection for cursors could be done in IDBRequest.)
Totally agree - been wanting to do that refactor for a while. Good catch on the inconsistency in setValueReady - I at least made it succeed gracefully with a FIXME.
Alec Flett
Comment 5
2012-07-25 15:58:21 PDT
Created
attachment 154467
[details]
Patch
Joshua Bell
Comment 6
2012-07-25 16:07:51 PDT
(In reply to
comment #4
)
> > (Thinking towards further refactors, it would be nice if the updated cursor key/primarykey/value were passed back in onSuccessWithContinuation, stashed in the IDBRequest itself (not the cursor) and then the key injection for cursors could be done in IDBRequest.) > > Totally agree - been wanting to do that refactor for a while.
FYI, I have that (mostly) done locally, tracking in
https://bugs.webkit.org/show_bug.cgi?id=92278
Needs to wait for the dust to settle, before breaking it up for landing, though.
Alec Flett
Comment 7
2012-07-25 16:09:42 PDT
Already referenced that but in the patch! :)
Joshua Bell
Comment 8
2012-07-25 16:19:27 PDT
Comment on
attachment 154467
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=154467&action=review
Did you see my question "Do we have any existing tests where the index key path is the same as the store's key path and autoincrement is used?"
> Source/WebCore/Modules/indexeddb/IDBCursor.cpp:258 > + const IDBObjectStoreMetadata metadata = objectStore->metadata();
To simplify, maybe we want to have IDBObjectStore::keyPath() return an IDBKeyPath and implement the IDL keyPath attribute via a method named keyPathAny() instead. Then we can ditch the metadata() uses here, and the IDBKeyPath::operator== can take an IDBKeyPaths instead of an IDBAny.
> Source/WebCore/Modules/indexeddb/IDBKeyPath.cpp:249 > + case ArrayType:
Missing an other->type() == IDBAny::DOMStringListType check?
> Source/WebCore/Modules/indexeddb/IDBRequest.cpp:360 > + ASSERT(keyPath == effectiveObjectStore(m_source)->keyPath());
Thanks, and sorry for the pain.
Alec Flett
Comment 9
2012-07-25 16:49:44 PDT
Created
attachment 154487
[details]
Patch
Alec Flett
Comment 10
2012-07-25 16:50:34 PDT
Comment on
attachment 154467
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=154467&action=review
>> Source/WebCore/Modules/indexeddb/IDBCursor.cpp:258 >> + const IDBObjectStoreMetadata metadata = objectStore->metadata(); > > To simplify, maybe we want to have IDBObjectStore::keyPath() return an IDBKeyPath and implement the IDL keyPath attribute via a method named keyPathAny() instead. > > Then we can ditch the metadata() uses here, and the IDBKeyPath::operator== can take an IDBKeyPaths instead of an IDBAny.
tried that but the binding code calls keyPath(), so we'd have to change the IDL... lets tackle that elsewhere
>> Source/WebCore/Modules/indexeddb/IDBKeyPath.cpp:249 >> + case ArrayType: > > Missing an other->type() == IDBAny::DOMStringListType check?
whoops! done.
Alec Flett
Comment 11
2012-07-25 17:04:08 PDT
sorry I keep ignoring the question about the tests - I keep meaning to answer then getting into other stuff. let me look now.
Alec Flett
Comment 12
2012-07-25 20:16:37 PDT
I can't find any at first pass. I suspect that currently most practical uses of that will fail in the current implementation. Specifically if you did: objectStore = createObjectStore("XX", {autoIncrement: true, keyPath: "foo"}) index = objectStore.createIndex("foo", "foo"); Then when you call put() you're almost certainly adding objects that have the "foo" property set: objectStore.put({"foo": "xyz"}) In the current code I believe this will fail because createObjectStore will look for the current key and fail because it's supposed to be autoIncrement. If you tried objectStore.put({}) Then I think the code might fail to generate an index key for "foo", then write the object to the autoIncremented new value, (because it does pre-generate the index keys first, even in the backend) and the same will happen after this patch, for wildly different reasons: because the key would be 'generated' until the object came out of the store. I'll have to think about how to fix that case.
Alec Flett
Comment 13
2012-07-26 14:17:26 PDT
Created
attachment 154748
[details]
Patch
Alec Flett
Comment 14
2012-07-26 14:18:35 PDT
ok, new patch includes a test for what we described above - sure enough, it was working on trunk, the previous patch broke it, so this new patch has a fix.
Joshua Bell
Comment 15
2012-07-26 14:58:18 PDT
Comment on
attachment 154748
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=154748&action=review
> Source/WebCore/ChangeLog:27 > + No new tests because this is a refactoring, and actual behavior
Update comment with new test name.
> Source/WebCore/Modules/indexeddb/IDBObjectStoreBackendImpl.cpp:286 > + if (indexKeyPath == objectStore->keyPath())
This creates an temporary IDBAny (via cast operator on IDBKeyPath); it would be nice to avoid it. (The other use of the IDBKeyPath::operator==(IDBAny) is in debug code.)
> LayoutTests/storage/indexeddb/resources/index-duplicate-keypaths.js:12 > + request.onsuccess = testCollideObjstoreIndexSetup;
The "Objstore" contraction is a little odd. Use "ObjStore", "ObjectStore" or just "Store".
> LayoutTests/storage/indexeddb/resources/index-duplicate-keypaths.js:21 > + request.onerror = unexpectedErrorCallback;
Catch onblocked too, please.
> LayoutTests/storage/indexeddb/resources/index-duplicate-keypaths.js:27 > + trans = event.target.result;
FYI, using |event.target.result| rather than |request.result| makes the test slightly more work to port to Workers (which don't have a global |event|). Not a big deal, though.
> LayoutTests/storage/indexeddb/resources/index-duplicate-keypaths.js:28 > + deleteAllObjectStores(db);
Duplicated.
> LayoutTests/storage/indexeddb/resources/index-duplicate-keypaths.js:40 > + shouldBeEqualToString("JSON.stringify(result)", v);
I'm slightly worried that the serialization order is indeterminate, but I suspect in practice it's sorted by key to avoid such issues. I agree this is probably the best way to do a quick compare of these sorts of values.
> LayoutTests/storage/indexeddb/resources/index-duplicate-keypaths.js:69 > + deleteAllObjectStores(db);
Duplicated.
> LayoutTests/storage/indexeddb/resources/index-duplicate-keypaths.js:84 > + // insert some data to futz with the autoIncrement state
Capitalize, punctuate.
> LayoutTests/storage/indexeddb/resources/index-duplicate-keypaths.js:86 > + objectStore.put({foo: i});
Can you do this in an evalAndLog() so a reader of the expected.txt knows what's going on?
> LayoutTests/storage/indexeddb/resources/index-duplicate-keypaths.js:90 > + debug("got back " + JSON.stringify(event.target.result));
I think this debug() line is redundant with the following shouldBe() call.
Alec Flett
Comment 16
2012-07-26 15:36:39 PDT
Comment on
attachment 154748
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=154748&action=review
test issues addressed.
>> Source/WebCore/Modules/indexeddb/IDBObjectStoreBackendImpl.cpp:286 >> + if (indexKeyPath == objectStore->keyPath()) > > This creates an temporary IDBAny (via cast operator on IDBKeyPath); it would be nice to avoid it. (The other use of the IDBKeyPath::operator==(IDBAny) is in debug code.)
That's only in the FRONT end - in the backend, keyPath() returns an IDBKeyPath (Another reason to fix that!)
Alec Flett
Comment 17
2012-07-26 15:37:11 PDT
Created
attachment 154772
[details]
Patch
Alec Flett
Comment 18
2012-07-26 16:01:19 PDT
Created
attachment 154776
[details]
Patch
Alec Flett
Comment 19
2012-07-26 16:04:28 PDT
the patch for cleaning up the keyPath() junk is
bug 92434
Alec Flett
Comment 20
2012-07-26 16:10:59 PDT
Created
attachment 154780
[details]
Patch
Alec Flett
Comment 21
2012-07-26 16:22:39 PDT
tony@ - r?
Tony Chang
Comment 22
2012-07-26 16:57:26 PDT
Comment on
attachment 154780
[details]
Patch rs=me
WebKit Review Bot
Comment 23
2012-07-27 00:30:51 PDT
Comment on
attachment 154780
[details]
Patch Clearing flags on attachment: 154780 Committed
r123843
: <
http://trac.webkit.org/changeset/123843
>
WebKit Review Bot
Comment 24
2012-07-27 00:30:57 PDT
All reviewed patches have been landed. Closing bug.
Note
You need to
log in
before you can comment on or make changes to this bug.
Top of Page
Format For Printing
XML
Clone This Bug