Chromium Code Reviews| Index: third_party/WebKit/Source/modules/indexeddb/IDBRequest.h |
| diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBRequest.h b/third_party/WebKit/Source/modules/indexeddb/IDBRequest.h |
| index 8d87624bcac2d2d92a7ef8b6ce0b121e7b11925d..1194dd4d5cd8ebdc6860a80b81da5a6588182f05 100644 |
| --- a/third_party/WebKit/Source/modules/indexeddb/IDBRequest.h |
| +++ b/third_party/WebKit/Source/modules/indexeddb/IDBRequest.h |
| @@ -46,6 +46,7 @@ |
| #include "platform/blob/BlobData.h" |
| #include "platform/heap/Handle.h" |
| #include "platform/wtf/HashMap.h" |
| +#include "platform/wtf/RefPtr.h" |
| #include "public/platform/WebBlobInfo.h" |
| #include "public/platform/modules/indexeddb/WebIDBCursor.h" |
| #include "public/platform/modules/indexeddb/WebIDBTypes.h" |
| @@ -112,24 +113,54 @@ class MODULES_EXPORT IDBRequest : public EventTargetWithInlineData, |
| void SetPendingCursor(IDBCursor*); |
| void Abort(); |
| - void EnqueueResponse(DOMException*); |
| - void EnqueueResponse(std::unique_ptr<WebIDBCursor>, |
| - IDBKey*, |
| - IDBKey* primary_key, |
| - PassRefPtr<IDBValue>); |
| - void EnqueueResponse(IDBKey*); |
| - void EnqueueResponse(PassRefPtr<IDBValue>); |
| - void EnqueueResponse(const Vector<RefPtr<IDBValue>>&); |
| - void EnqueueResponse(); |
| - void EnqueueResponse(IDBKey*, IDBKey* primary_key, PassRefPtr<IDBValue>); |
| + // Blink's delivery of results from IndexedDB's backing store to script is |
| + // more complicated than prescribed in the IndexedDB specification. |
| + // |
| + // IDBValue, which holds responses from the backing store, is either the |
| + // serialized V8 value, or a reference to a Blob that holds the serialized |
| + // value. IDBValueWrapping.h has the motivation and details. This introduces |
| + // the following complexities. |
| + // |
| + // 1) De-serialization is expensive, so it is done lazily in |
| + // IDBRequest::result(), which is called synchronously from script. On the |
| + // other hand, Blob data can only be fetched asynchronously. So, IDBValues |
| + // that reference serialized data stored in Blobs must be processed before |
| + // IDBRequest event handlers are invoked, because the event handler script may |
| + // call IDBRequest::result(). |
| + // |
| + // 2) The IDBRequest events must be dispatched (enqueued in DOMWindow's event |
| + // queue) in the order in which the requests were issued. If an IDBValue |
| + // references a Blob, the Blob processing must block event dispatch for all |
| + // following IDBRequests in the same transaction. |
| + // |
| + // The Blob de-referencing and IDBRequest blocking is performed in the |
| + // HandleResponse() overloads below. Each HandleResponse() overload is paired |
| + // with a matching EnqueueResponse() overload, which is called when an |
| + // IDBRequest's result event can be delivered to the application. All the |
| + // HandleResponse() variants include a fast path that calls directly into |
| + // EnqueueResponse() if no queueing is required. |
| + // |
| + // Some types of requests, such as indexedDB.openDatabase(), cannot be issued |
|
jsbell
2017/05/22 21:54:19
How about: "IDBOpenDBRequests are not associated w
pwnall
2017/05/25 13:27:11
I like your explanation, because it's simpler, but
|
| + // after a request that needs Blob processing, so their results are handled by |
| + // having WebIDBCallbacksImpl call directly into EnqueueResponse(), |
| + // EnqueueBlocked(), or EnqueueUpgradeNeeded(). |
| + |
| + void HandleResponse(DOMException*); |
| + void HandleResponse(IDBKey*); |
| + void HandleResponse(std::unique_ptr<WebIDBCursor>, |
| + IDBKey*, |
| + IDBKey* primary_key, |
| + RefPtr<IDBValue>&&); |
| + void HandleResponse(IDBKey*, IDBKey* primary_key, RefPtr<IDBValue>&&); |
| + void HandleResponse(RefPtr<IDBValue>&&); |
| + void HandleResponse(const Vector<RefPtr<IDBValue>>&); |
| + void HandleResponse(int64_t); |
| + void HandleResponse(); |
| // Only used in webkitGetDatabaseNames(), which is deprecated and hopefully |
| // going away soon. |
| void EnqueueResponse(const Vector<String>&); |
| - // Overridden by IDBOpenDBRequest. |
| - virtual void EnqueueResponse(int64_t); |
| - |
| // Only IDBOpenDBRequest instances should receive these: |
| virtual void EnqueueBlocked(int64_t old_version) { NOTREACHED(); } |
| virtual void EnqueueUpgradeNeeded(int64_t old_version, |
| @@ -162,11 +193,29 @@ class MODULES_EXPORT IDBRequest : public EventTargetWithInlineData, |
| IDBCursor* GetResultCursor() const; |
| - void StorePutOperationBlobs( |
| - HashMap<String, RefPtr<BlobDataHandle>> blob_handles) { |
| - transit_blob_handles_ = std::move(blob_handles); |
| + // Used to hang onto Blobs until the browser process handles the request. |
| + // |
| + // Blobs are ref-counted on the browser side, and BlobDataHandles manage |
| + // references from renderers. When a BlobDataHandle gets destroyed, the |
| + // browser-side Blob gets derefenced, which might cause it to be destroyed as |
| + // well. |
| + // |
| + // After script uses a Blob in a put() request, the Blink-side Blob object |
| + // (which hangs onto the BlobDataHandle) may get garbage-collected. IDBRequest |
| + // needs to hang onto the BlobDataHandle as well, to avoid having the |
| + // browser-side Blob get destroyed before the IndexedDB request is processed. |
| + inline Vector<RefPtr<BlobDataHandle>>* transit_blob_handles() { |
| + return &transit_blob_handles_; |
| } |
| +#if DCHECK_IS_ON() |
| + inline bool TransactionHasQueuedResults() const { |
| + return transaction_ && transaction_->HasQueuedResults(); |
| + } |
| + |
| + inline IDBRequestQueueItem* QueueItem() const { return queue_item_; } |
| +#endif // DCHECK_IS_ON() |
| + |
| protected: |
| IDBRequest(ScriptState*, IDBAny* source, IDBTransaction*); |
| void EnqueueEvent(Event*); |
| @@ -175,10 +224,16 @@ class MODULES_EXPORT IDBRequest : public EventTargetWithInlineData, |
| void EnqueueResultInternal(IDBAny*); |
| void SetResult(IDBAny*); |
| + // Overridden by IDBOpenDBRequest. |
| + virtual void EnqueueResponse(int64_t); |
| + |
| // EventTarget |
| DispatchEventResult DispatchEventInternal(Event*) override; |
| + // Can be nullptr for requests that are not associated with a transaction, |
| + // i.e. delete requests and completed or unsuccessful open requests. |
| Member<IDBTransaction> transaction_; |
| + |
| ReadyState ready_state_ = PENDING; |
| bool request_aborted_ = false; // May be aborted by transaction then receive |
| // async onsuccess; ignore vs. assert. |
| @@ -187,14 +242,26 @@ class MODULES_EXPORT IDBRequest : public EventTargetWithInlineData, |
| v8::Isolate* isolate_; |
| private: |
| + // Calls EnqueueResponse(). |
| + friend class IDBRequestQueueItem; |
| + |
| void SetResultCursor(IDBCursor*, |
| IDBKey*, |
| IDBKey* primary_key, |
| - PassRefPtr<IDBValue>); |
| + RefPtr<IDBValue>&&); |
| void AckReceivedBlobs(const IDBValue*); |
| void AckReceivedBlobs(const Vector<RefPtr<IDBValue>>&); |
| - void ClearPutOperationBlobs() { transit_blob_handles_.clear(); } |
| + void EnqueueResponse(DOMException*); |
| + void EnqueueResponse(IDBKey*); |
| + void EnqueueResponse(std::unique_ptr<WebIDBCursor>, |
| + IDBKey*, |
| + IDBKey* primary_key, |
| + RefPtr<IDBValue>&&); |
| + void EnqueueResponse(IDBKey*, IDBKey* primary_key, RefPtr<IDBValue>&&); |
| + void EnqueueResponse(RefPtr<IDBValue>&&); |
| + void EnqueueResponse(const Vector<RefPtr<IDBValue>>&); |
| + void EnqueueResponse(); |
| Member<IDBAny> source_; |
| Member<IDBAny> result_; |
| @@ -215,7 +282,7 @@ class MODULES_EXPORT IDBRequest : public EventTargetWithInlineData, |
| Member<IDBKey> cursor_primary_key_; |
| RefPtr<IDBValue> cursor_value_; |
| - HashMap<String, RefPtr<BlobDataHandle>> transit_blob_handles_; |
| + Vector<RefPtr<BlobDataHandle>> transit_blob_handles_; |
| bool did_fire_upgrade_needed_event_ = false; |
| bool prevent_propagation_ = false; |
| @@ -230,6 +297,12 @@ class MODULES_EXPORT IDBRequest : public EventTargetWithInlineData, |
| // Pointer back to the WebIDBCallbacks that holds a persistent reference to |
| // this object. |
| WebIDBCallbacks* web_callbacks_ = nullptr; |
| + |
| +#if DCHECK_IS_ON() |
| + // Non-null while this request is queued behind other requests that are still |
| + // getting post-processed. |
| + IDBRequestQueueItem* queue_item_ = nullptr; |
| +#endif // DCHECK_IS_ON() |
| }; |
| } // namespace blink |